Remove EventPublisher macros

This commit is contained in:
Teddy Reed 2014-12-14 04:43:31 -07:00
parent 353b44c6cc
commit 0d00e4b0e9
4 changed files with 141 additions and 157 deletions

View File

@ -19,6 +19,8 @@
namespace osquery {
struct Subscription;
template <class SC, class EC>
class EventPublisher;
class EventSubscriber;
@ -62,7 +64,8 @@ struct EventContext {
};
typedef std::shared_ptr<Subscription> SubscriptionRef;
typedef std::shared_ptr<EventPublisher> EventPublisherRef;
typedef std::shared_ptr<EventPublisher<SubscriptionContext, EventContext> >
EventPublisherRef;
typedef std::shared_ptr<SubscriptionContext> SubscriptionContextRef;
typedef std::shared_ptr<EventContext> EventContextRef;
typedef std::shared_ptr<EventSubscriber> EventSubscriberRef;
@ -78,49 +81,6 @@ typedef std::map<EventPublisherID, EventPublisherRef> EventPublisherMap;
/// The set of search-time binned lookup tables.
extern const std::vector<size_t> kEventTimeLists;
/**
* @brief Helper type casting methods for EventPublisher classes.
*
* A new osquery EventPublisher should subclass EventPublisher and use the
* following:
*
* @code{.cpp}
* #include <osquery/events.h>
*
* 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<EVENT> getEventContext(EventContextRef context) { \
return std::static_pointer_cast<EVENT>(context); \
} \
static std::shared_ptr<MONITOR> getSubscriptionContext( \
SubscriptionContextRef context) { \
return std::static_pointer_cast<MONITOR>(context); \
} \
static std::shared_ptr<EVENT> createEventContext() { \
return std::make_shared<EVENT>(); \
} \
static std::shared_ptr<MONITOR> createSubscriptionContext() { \
return std::make_shared<MONITOR>(); \
}
/**
* @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 <typename SC, typename EC>
class EventPublisher {
typedef std::shared_ptr<SC> SCRef;
typedef std::shared_ptr<EC> 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 <typename T>
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>(ec);
}
static SCRef getSubscriptionContext(SubscriptionContextRef sc) {
return std::static_pointer_cast<SC>(sc);
}
static ECRef createEventContext() { return std::make_shared<EC>(); }
static SCRef createSubscriptionContext() { return std::make_shared<SC>(); }
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 <typename T>
template <class T>
static Status registerEventPublisher() {
auto event_pub = std::make_shared<T>();
return EventFactory::registerEventPublisher(event_pub);
auto pub = std::make_shared<T>();
return registerEventPublisher<T>(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 <class T>
static Status registerEventPublisher(std::shared_ptr<T> pub) {
auto base_pub = reinterpret_cast<EventPublisherRef&>(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 <typename T>
static Status addSubscription(const SubscriptionContextRef mc,
EventCallback cb = 0) {
return addSubscription(EventPublisher::type<T>(), mc, cb);
return addSubscription(T::type(), mc, cb);
}
/// Add a Subscription by templating the EventPublisher, using a Subscription
/// instance.
template <typename T>
static Status addSubscription(const SubscriptionRef subscription) {
return addSubscription(EventPublisher::type<T>(), 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 <typename T>
static void fire(const EventContextRef ec) {
auto event_pub = getEventPublisher(EventPublisher::type<T>());
auto event_pub = getEventPublisher(T::type());
event_pub->fire(ec);
}

View File

@ -30,7 +30,8 @@ const std::vector<size_t> kEventTimeLists = {
10, // 10 seconds
};
void EventPublisher::fire(const EventContextRef ec, EventTime time) {
template <typename SC, typename EC>
void EventPublisher<SC, EC>::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<SubscriptionContext, EventContext>;
std::vector<std::string> 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<EventPublisher> 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()) {

View File

@ -34,8 +34,10 @@ class FakeEventSubscriber : public EventSubscriber {
}
};
class FakeEventPublisher : public EventPublisher {
DECLARE_EVENTPUBLISHER(FakeEventPublisher, SubscriptionContext, EventContext);
class FakeEventPublisher
: public EventPublisher<SubscriptionContext, EventContext> {
public:
EventPublisherID type() { return "Fake"; }
};
class AnotherFakeEventSubscriber : public EventSubscriber {

View File

@ -1,5 +1,7 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <typeinfo>
#include <gtest/gtest.h>
#include <osquery/events.h>
@ -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<SubscriptionContext, EventContext> {};
class AnotherBasicEventPublisher
: public EventPublisher<SubscriptionContext, EventContext> {};
// Create some still-useless subscription and event structures.
struct FakeSubscriptionContext : SubscriptionContext {};
struct FakeEventContext : EventContext {};
// Typdef the shared_ptr accessors.
typedef std::shared_ptr<FakeSubscriptionContext> FakeSubscriptionContextRef;
typedef std::shared_ptr<FakeEventContext> FakeEventContextRef;
// Now a publisher with a type.
class FakeEventPublisher
: public EventPublisher<FakeSubscriptionContext, FakeEventContext> {
public:
EventPublisherID type() { return "Fake"; }
};
class FakeBasicEventPublisher : public EventPublisher {
DECLARE_EVENTPUBLISHER(FakeBasicEventPublisher,
SubscriptionContext,
EventContext);
class AnotherFakeEventPublisher
: public EventPublisher<FakeSubscriptionContext, FakeEventContext> {
public:
EventPublisherID type() { return "AnotherFake"; }
};
TEST_F(EventsTests, test_event_pub) {
auto pub = std::make_shared<FakeEventPublisher>();
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<BasicEventPublisher>();
// This template class is equivilent to the reinterpret casting target.
auto status = EventFactory::registerEventPublisher<BasicEventPublisher>();
EXPECT_TRUE(status.ok());
// This class is the SAME, there was no type override.
status = EventFactory::registerEventPublisher<AnotherBasicEventPublisher>();
EXPECT_FALSE(status.ok());
// This class is different but also uses different types!
status = EventFactory::registerEventPublisher<FakeEventPublisher>();
EXPECT_TRUE(status.ok());
// May also register the event_pub instance
auto event_pub_instance = std::make_shared<FakeBasicEventPublisher>();
status = EventFactory::registerEventPublisher(event_pub_instance);
auto pub = std::make_shared<AnotherFakeEventPublisher>();
status = EventFactory::registerEventPublisher<AnotherFakeEventPublisher>(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<BasicEventPublisher>();
auto status = EventFactory::registerEventPublisher<BasicEventPublisher>();
EXPECT_TRUE(status.ok());
// Do not register the same event type twice.
status = EventFactory::registerEventPublisher<BasicEventPublisher>();
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<BasicEventPublisher>();
// 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<BasicEventPublisher>();
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<TestSubscriptionContext, EventContext> {
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<BasicEventPublisher>();
auto test_event_pub = std::make_shared<TestEventPublisher>();
status = EventFactory::registerEventPublisher(test_event_pub);
auto status = EventFactory::registerEventPublisher<BasicEventPublisher>();
auto pub = std::make_shared<TestEventPublisher>();
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<TestEventPublisher>();
status = EventFactory::registerEventPublisher(event_pub);
auto pub = std::make_shared<TestEventPublisher>();
auto status = EventFactory::registerEventPublisher(pub);
// Step 2, create and configure a subscription context
auto subscription_context = std::make_shared<TestSubscriptionContext>();
subscription_context->smallest = -1;
auto sc = std::make_shared<TestSubscriptionContext>();
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<TestEventPublisher>();
status = EventFactory::registerEventPublisher(event_pub);
auto pub = std::make_shared<TestEventPublisher>();
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<BasicEventPublisher>();
status = EventFactory::registerEventPublisher(event_pub);
auto pub = std::make_shared<BasicEventPublisher>();
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);
}
}