From 0d00e4b0e98ef50d42ead7082bae517ca8e1d9d8 Mon Sep 17 00:00:00 2001 From: Teddy Reed Date: Sun, 14 Dec 2014 04:43:31 -0700 Subject: [PATCH] Remove EventPublisher macros --- include/osquery/events.h | 105 ++++++--------- osquery/events/events.cpp | 29 ++--- osquery/events/events_database_tests.cpp | 6 +- osquery/events/events_tests.cpp | 158 ++++++++++++----------- 4 files changed, 141 insertions(+), 157 deletions(-) diff --git a/include/osquery/events.h b/include/osquery/events.h index 5a3367dc..9ab1aafc 100644 --- a/include/osquery/events.h +++ b/include/osquery/events.h @@ -19,6 +19,8 @@ namespace osquery { struct Subscription; + +template class EventPublisher; class EventSubscriber; @@ -62,7 +64,8 @@ struct EventContext { }; typedef std::shared_ptr SubscriptionRef; -typedef std::shared_ptr EventPublisherRef; +typedef std::shared_ptr > +EventPublisherRef; typedef std::shared_ptr SubscriptionContextRef; typedef std::shared_ptr EventContextRef; typedef std::shared_ptr EventSubscriberRef; @@ -78,49 +81,6 @@ typedef std::map EventPublisherMap; /// The set of search-time binned lookup tables. extern const std::vector kEventTimeLists; -/** - * @brief Helper type casting methods for EventPublisher classes. - * - * A new osquery EventPublisher should subclass EventPublisher and use the - * following: - * - * @code{.cpp} - * #include - * - * class MyEventPublisher: public EventPublisher { - * DECLARE_EVENTPUBLISHER(MyEventPublisher, MySubscriptionContext, - * MyEventContext); - * } - * @endcode - * - * This assumes new EventPublisher%s will always include a custom - * SubscriptionContext and EventContext. In the above example - * MySubscriptionContext allows EventSubscriber%s to downselect or customize - * what events to handle. And MyEventContext includes fields specific to the - * new EventPublisher. - */ -#define DECLARE_EVENTPUBLISHER(TYPE, MONITOR, EVENT) \ - public: \ - EventPublisherID type() const { return #TYPE; } \ - bool shouldFire(const SubscriptionContextRef mc, const EventContextRef ec) { \ - if (#MONITOR == "SubscriptionContext" && #EVENT == "EventContext") \ - return true; \ - return shouldFire(getSubscriptionContext(mc), getEventContext(ec)); \ - } \ - static std::shared_ptr getEventContext(EventContextRef context) { \ - return std::static_pointer_cast(context); \ - } \ - static std::shared_ptr getSubscriptionContext( \ - SubscriptionContextRef context) { \ - return std::static_pointer_cast(context); \ - } \ - static std::shared_ptr createEventContext() { \ - return std::make_shared(); \ - } \ - static std::shared_ptr createSubscriptionContext() { \ - return std::make_shared(); \ - } - /** * @brief Required getter and namespace helper methods for EventSubscriber%s. * @@ -308,7 +268,11 @@ struct Subscription { * only call the Subscription%'s callback function is the EventContext * (thus event) matches. */ +template class EventPublisher { + typedef std::shared_ptr SCRef; + typedef std::shared_ptr ECRef; + public: /** * @brief A new Subscription was added, potentially change state based on all @@ -329,7 +293,7 @@ class EventPublisher { * When `setUp` is called the EventPublisher is running in a dedicated thread * and may manage/allocate/wait for resources. */ - virtual Status setUp() { return Status(0, "Not used."); } + virtual Status setUp() { return Status(0, "Not used"); } /** * @brief Perform handle closing, resource cleanup. @@ -345,7 +309,7 @@ class EventPublisher { * @return A SUCCESS status will immediately call `run` again. A FAILED status * will exit the run loop and the thread. */ - virtual Status run(); + virtual Status run() { return Status(1, "No runloop required"); } /** * @brief A new EventSubscriber is subscriptioning events of this @@ -376,16 +340,7 @@ class EventPublisher { virtual ~EventPublisher() {} /// Return a string identifier associated with this EventPublisher. - virtual EventPublisherID type() const = 0; - - /// Return a string identifier for the given EventPublisher symbol. - template - static EventPublisherID type() { - const auto& event_pub = new T(); - auto type_id = event_pub->type(); - delete event_pub; - return type_id; - } + virtual EventPublisherID type() { return "publisher"; } public: /** @@ -399,6 +354,19 @@ class EventPublisher { */ void fire(const EventContextRef ec, EventTime time = 0); + public: + /// Templating accessors/factories. + static ECRef getEventContext(EventContextRef ec) { + return std::static_pointer_cast(ec); + } + + static SCRef getSubscriptionContext(SubscriptionContextRef sc) { + return std::static_pointer_cast(sc); + } + + static ECRef createEventContext() { return std::make_shared(); } + static SCRef createSubscriptionContext() { return std::make_shared(); } + protected: /** * @brief The generic `fire` will call `shouldFire` for each Subscription. @@ -409,8 +377,7 @@ class EventPublisher { * * @return should the Subscription%'s EventCallback be called for this event. */ - virtual bool shouldFire(const SubscriptionContextRef mc, - const EventContextRef ec); + virtual bool shouldFire(const SCRef sc, const ECRef ec) { return true; } protected: /// The EventPublisher will keep track of Subscription%s that contain callins. @@ -425,6 +392,7 @@ class EventPublisher { boost::mutex ec_id_lock_; private: + FRIEND_TEST(EventsTests, test_event_pub); FRIEND_TEST(EventsTests, test_fire_event); }; @@ -600,6 +568,7 @@ class EventSubscriber { boost::mutex event_record_lock_; private: + FRIEND_TEST(EventsTests, test_event_sub); FRIEND_TEST(EventsDatabaseTests, test_event_module_id); FRIEND_TEST(EventsDatabaseTests, test_unique_event_module_id); FRIEND_TEST(EventsDatabaseTests, test_record_indexing); @@ -627,10 +596,10 @@ class EventFactory { * * The registration is mostly abstracted using osquery's registery. */ - template + template static Status registerEventPublisher() { - auto event_pub = std::make_shared(); - return EventFactory::registerEventPublisher(event_pub); + auto pub = std::make_shared(); + return registerEventPublisher(pub); } /** @@ -644,7 +613,13 @@ class EventFactory { * Access to the EventPublisher instance is not discouraged, but using the * EventFactory `getEventPublisher` accessor is encouraged. */ - static Status registerEventPublisher(const EventPublisherRef event_pub); + template + static Status registerEventPublisher(std::shared_ptr pub) { + auto base_pub = reinterpret_cast(pub); + return registerEventPublisher(base_pub); + } + + static Status registerEventPublisher(const EventPublisherRef pub); /** * @brief Add an EventSubscriber to the factory. @@ -699,14 +674,14 @@ class EventFactory { template static Status addSubscription(const SubscriptionContextRef mc, EventCallback cb = 0) { - return addSubscription(EventPublisher::type(), mc, cb); + return addSubscription(T::type(), mc, cb); } /// Add a Subscription by templating the EventPublisher, using a Subscription /// instance. template static Status addSubscription(const SubscriptionRef subscription) { - return addSubscription(EventPublisher::type(), subscription); + return addSubscription(T::type(), subscription); } /// Get the total number of Subscription%s across ALL EventPublisher%s. @@ -750,7 +725,7 @@ class EventFactory { /// If a static EventPublisher callback wants to fire template static void fire(const EventContextRef ec) { - auto event_pub = getEventPublisher(EventPublisher::type()); + auto event_pub = getEventPublisher(T::type()); event_pub->fire(ec); } diff --git a/osquery/events/events.cpp b/osquery/events/events.cpp index 29d2812c..e41da6a6 100644 --- a/osquery/events/events.cpp +++ b/osquery/events/events.cpp @@ -30,7 +30,8 @@ const std::vector kEventTimeLists = { 10, // 10 seconds }; -void EventPublisher::fire(const EventContextRef ec, EventTime time) { +template +void EventPublisher::fire(const EventContextRef ec, EventTime time) { EventContextID ec_id; { @@ -55,21 +56,16 @@ void EventPublisher::fire(const EventContextRef ec, EventTime time) { for (const auto& subscription : subscriptions_) { auto callback = subscription->callback; - if (shouldFire(subscription->context, ec) && callback != nullptr) { + if (shouldFire(getSubscriptionContext(subscription->context), + getEventContext(ec)) && + callback != nullptr) { callback(ec, false); } } } -bool EventPublisher::shouldFire(const SubscriptionContextRef mc, - const EventContextRef ec) { - return true; -} - -Status EventPublisher::run() { - // Runloops/entrypoints are ONLY implemented if needed. - return Status(1, "No runloop required"); -} +/// Force generation of EventPublisher::fire +template class EventPublisher; std::vector EventSubscriber::getIndexes(EventTime start, EventTime stop, @@ -417,21 +413,21 @@ EventFactory& EventFactory::getInstance() { return ef; } -Status EventFactory::registerEventPublisher(const EventPublisherRef event_pub) { +Status EventFactory::registerEventPublisher(const EventPublisherRef pub) { auto& ef = EventFactory::getInstance(); - auto type_id = event_pub->type(); + auto type_id = pub->type(); if (ef.getEventPublisher(type_id) != nullptr) { // This is a duplicate type id? return Status(1, "Duplicate Event Type"); } - if (!event_pub->setUp().ok()) { + if (!pub->setUp().ok()) { // Only add the publisher if setUp was successful. return Status(1, "SetUp failed."); } - ef.event_pubs_[type_id] = event_pub; + ef.event_pubs_[type_id] = pub; return Status(0, "OK"); } @@ -474,8 +470,7 @@ size_t EventFactory::numSubscriptions(EventPublisherID type_id) { return 0; } -std::shared_ptr EventFactory::getEventPublisher( - EventPublisherID type_id) { +EventPublisherRef EventFactory::getEventPublisher(EventPublisherID type_id) { auto& ef = EventFactory::getInstance(); const auto& it = ef.event_pubs_.find(type_id); if (it != ef.event_pubs_.end()) { diff --git a/osquery/events/events_database_tests.cpp b/osquery/events/events_database_tests.cpp index b189b91f..5ea338b5 100644 --- a/osquery/events/events_database_tests.cpp +++ b/osquery/events/events_database_tests.cpp @@ -34,8 +34,10 @@ class FakeEventSubscriber : public EventSubscriber { } }; -class FakeEventPublisher : public EventPublisher { - DECLARE_EVENTPUBLISHER(FakeEventPublisher, SubscriptionContext, EventContext); +class FakeEventPublisher + : public EventPublisher { + public: + EventPublisherID type() { return "Fake"; } }; class AnotherFakeEventSubscriber : public EventSubscriber { diff --git a/osquery/events/events_tests.cpp b/osquery/events/events_tests.cpp index 974f482d..f78a1bcc 100644 --- a/osquery/events/events_tests.cpp +++ b/osquery/events/events_tests.cpp @@ -1,5 +1,7 @@ // Copyright 2004-present Facebook. All Rights Reserved. +#include + #include #include @@ -7,71 +9,91 @@ namespace osquery { -class EventsTests : public testing::Test { +class EventsTests : public ::testing::Test { public: void TearDown() { EventFactory::deregisterEventPublishers(); } }; -class BasicEventPublisher : public EventPublisher { - DECLARE_EVENTPUBLISHER(BasicEventPublisher, - SubscriptionContext, - EventContext); +// The most basic event publisher uses useless Subscription/Event. +class BasicEventPublisher + : public EventPublisher {}; +class AnotherBasicEventPublisher + : public EventPublisher {}; + +// Create some still-useless subscription and event structures. +struct FakeSubscriptionContext : SubscriptionContext {}; +struct FakeEventContext : EventContext {}; + +// Typdef the shared_ptr accessors. +typedef std::shared_ptr FakeSubscriptionContextRef; +typedef std::shared_ptr FakeEventContextRef; + +// Now a publisher with a type. +class FakeEventPublisher + : public EventPublisher { + public: + EventPublisherID type() { return "Fake"; } }; -class FakeBasicEventPublisher : public EventPublisher { - DECLARE_EVENTPUBLISHER(FakeBasicEventPublisher, - SubscriptionContext, - EventContext); +class AnotherFakeEventPublisher + : public EventPublisher { + public: + EventPublisherID type() { return "AnotherFake"; } }; +TEST_F(EventsTests, test_event_pub) { + auto pub = std::make_shared(); + EXPECT_EQ(pub->type(), "Fake"); + + // Test type names. + auto pub_sub = pub->createSubscriptionContext(); + EXPECT_EQ(typeid(FakeSubscriptionContext), typeid(*pub_sub)); +} + TEST_F(EventsTests, test_register_event_pub) { - Status status; - // A caller may register an event type using the class template. - status = EventFactory::registerEventPublisher(); + // This template class is equivilent to the reinterpret casting target. + auto status = EventFactory::registerEventPublisher(); + EXPECT_TRUE(status.ok()); + + // This class is the SAME, there was no type override. + status = EventFactory::registerEventPublisher(); + EXPECT_FALSE(status.ok()); + + // This class is different but also uses different types! + status = EventFactory::registerEventPublisher(); EXPECT_TRUE(status.ok()); // May also register the event_pub instance - auto event_pub_instance = std::make_shared(); - status = EventFactory::registerEventPublisher(event_pub_instance); + auto pub = std::make_shared(); + status = EventFactory::registerEventPublisher(pub); EXPECT_TRUE(status.ok()); - - // May NOT register without subclassing, enforced at compile time. } TEST_F(EventsTests, test_create_event_pub) { - Status status; - - status = EventFactory::registerEventPublisher(); + auto status = EventFactory::registerEventPublisher(); EXPECT_TRUE(status.ok()); - // Do not register the same event type twice. - status = EventFactory::registerEventPublisher(); - EXPECT_FALSE(status.ok()); - // Make sure only the first event type was recorded. EXPECT_EQ(EventFactory::numEventPublishers(), 1); } TEST_F(EventsTests, test_create_subscription) { - Status status; - EventFactory::registerEventPublisher(); // Make sure a subscription cannot be added for a non-existent event type. // Note: It normally would not make sense to create a blank subscription. auto subscription = Subscription::create(); - status = - EventFactory::addSubscription("FakeBasicEventPublisher", subscription); + auto status = EventFactory::addSubscription("Fake", subscription); EXPECT_FALSE(status.ok()); // In this case we can still add a blank subscription to an existing event // type. - status = EventFactory::addSubscription("BasicEventPublisher", subscription); + status = EventFactory::addSubscription("publisher", subscription); EXPECT_TRUE(status.ok()); // Make sure the subscription is added. - EXPECT_EQ(EventFactory::numSubscriptions("BasicEventPublisher"), 1); + EXPECT_EQ(EventFactory::numSubscriptions("publisher"), 1); } TEST_F(EventsTests, test_multiple_subscriptions) { @@ -80,22 +102,20 @@ TEST_F(EventsTests, test_multiple_subscriptions) { EventFactory::registerEventPublisher(); auto subscription = Subscription::create(); - status = EventFactory::addSubscription("BasicEventPublisher", subscription); - status = EventFactory::addSubscription("BasicEventPublisher", subscription); + status = EventFactory::addSubscription("publisher", subscription); + status = EventFactory::addSubscription("publisher", subscription); - EXPECT_EQ(EventFactory::numSubscriptions("BasicEventPublisher"), 2); + EXPECT_EQ(EventFactory::numSubscriptions("publisher"), 2); } struct TestSubscriptionContext : public SubscriptionContext { int smallest; }; -class TestEventPublisher : public EventPublisher { - DECLARE_EVENTPUBLISHER(TestEventPublisher, - TestSubscriptionContext, - EventContext); - +class TestEventPublisher + : public EventPublisher { public: + EventPublisherID type() { return "Test"; } Status setUp() { smallest_ever_ += 1; return Status(0, "OK"); @@ -133,65 +153,58 @@ class TestEventPublisher : public EventPublisher { }; TEST_F(EventsTests, test_create_custom_event_pub) { - Status status; - - status = EventFactory::registerEventPublisher(); - auto test_event_pub = std::make_shared(); - status = EventFactory::registerEventPublisher(test_event_pub); + auto status = EventFactory::registerEventPublisher(); + auto pub = std::make_shared(); + status = EventFactory::registerEventPublisher(pub); // These event types have unique event type IDs EXPECT_TRUE(status.ok()); EXPECT_EQ(EventFactory::numEventPublishers(), 2); // Make sure the setUp function was called. - EXPECT_EQ(test_event_pub->getTestValue(), 1); + EXPECT_EQ(pub->getTestValue(), 1); } TEST_F(EventsTests, test_custom_subscription) { - Status status; - // Step 1, register event type - auto event_pub = std::make_shared(); - status = EventFactory::registerEventPublisher(event_pub); + auto pub = std::make_shared(); + auto status = EventFactory::registerEventPublisher(pub); // Step 2, create and configure a subscription context - auto subscription_context = std::make_shared(); - subscription_context->smallest = -1; + auto sc = std::make_shared(); + sc->smallest = -1; // Step 3, add the subscription to the event type - status = - EventFactory::addSubscription("TestEventPublisher", subscription_context); + status = EventFactory::addSubscription("Test", sc); EXPECT_TRUE(status.ok()); - EXPECT_EQ(event_pub->numSubscriptions(), 1); + EXPECT_EQ(pub->numSubscriptions(), 1); // The event type must run configure for each added subscription. - EXPECT_TRUE(event_pub->configure_run); - EXPECT_EQ(event_pub->getTestValue(), -1); + EXPECT_TRUE(pub->configure_run); + EXPECT_EQ(pub->getTestValue(), -1); } TEST_F(EventsTests, test_tear_down) { - Status status; - - auto event_pub = std::make_shared(); - status = EventFactory::registerEventPublisher(event_pub); + auto pub = std::make_shared(); + auto status = EventFactory::registerEventPublisher(pub); // Make sure set up incremented the test value. - EXPECT_EQ(event_pub->getTestValue(), 1); + EXPECT_EQ(pub->getTestValue(), 1); - status = EventFactory::deregisterEventPublisher("TestEventPublisher"); + status = EventFactory::deregisterEventPublisher("Test"); EXPECT_TRUE(status.ok()); // Make sure tear down inremented the test value. - EXPECT_EQ(event_pub->getTestValue(), 2); + EXPECT_EQ(pub->getTestValue(), 2); // Once more, now deregistering all event types. - status = EventFactory::registerEventPublisher(event_pub); - EXPECT_EQ(event_pub->getTestValue(), 3); + status = EventFactory::registerEventPublisher(pub); + EXPECT_EQ(pub->getTestValue(), 3); status = EventFactory::deregisterEventPublishers(); EXPECT_TRUE(status.ok()); - EXPECT_EQ(event_pub->getTestValue(), 4); + EXPECT_EQ(pub->getTestValue(), 4); // Make sure the factory state represented. EXPECT_EQ(EventFactory::numEventPublishers(), 0); @@ -207,29 +220,28 @@ Status TestTheeCallback(EventContextRef context, bool reserved) { TEST_F(EventsTests, test_fire_event) { Status status; - auto event_pub = std::make_shared(); - status = EventFactory::registerEventPublisher(event_pub); + auto pub = std::make_shared(); + status = EventFactory::registerEventPublisher(pub); auto subscription = Subscription::create(); subscription->callback = TestTheeCallback; - status = EventFactory::addSubscription("BasicEventPublisher", subscription); + status = EventFactory::addSubscription("publisher", subscription); // The event context creation would normally happen in the event type. - auto ec = event_pub->createEventContext(); - event_pub->fire(ec, 0); + auto ec = pub->createEventContext(); + pub->fire(ec, 0); EXPECT_EQ(kBellHathTolled, 1); auto second_subscription = Subscription::create(); - status = - EventFactory::addSubscription("BasicEventPublisher", second_subscription); + status = EventFactory::addSubscription("publisher", second_subscription); // Now there are two subscriptions (one sans callback). - event_pub->fire(ec, 0); + pub->fire(ec, 0); EXPECT_EQ(kBellHathTolled, 2); // Now both subscriptions have callbacks. second_subscription->callback = TestTheeCallback; - event_pub->fire(ec, 0); + pub->fire(ec, 0); EXPECT_EQ(kBellHathTolled, 4); } }