ext/winevt/winevt_subscribe.c in winevt_c-0.5.1 vs ext/winevt/winevt_subscribe.c in winevt_c-0.6.0
- old
+ new
@@ -1,120 +1,141 @@
#include <winevt_c.h>
-static void subscribe_free(void *ptr);
+static void subscribe_free(void* ptr);
-static const rb_data_type_t rb_winevt_subscribe_type = {
- "winevt/subscribe", {
- 0, subscribe_free, 0,
- }, NULL, NULL,
- RUBY_TYPED_FREE_IMMEDIATELY
-};
+static const rb_data_type_t rb_winevt_subscribe_type = { "winevt/subscribe",
+ {
+ 0,
+ subscribe_free,
+ 0,
+ },
+ NULL,
+ NULL,
+ RUBY_TYPED_FREE_IMMEDIATELY };
static void
-subscribe_free(void *ptr)
+subscribe_free(void* ptr)
{
- struct WinevtSubscribe *winevtSubscribe = (struct WinevtSubscribe *)ptr;
+ struct WinevtSubscribe* winevtSubscribe = (struct WinevtSubscribe*)ptr;
if (winevtSubscribe->signalEvent)
CloseHandle(winevtSubscribe->signalEvent);
if (winevtSubscribe->subscription)
EvtClose(winevtSubscribe->subscription);
if (winevtSubscribe->bookmark)
EvtClose(winevtSubscribe->bookmark);
- if (winevtSubscribe->event)
- EvtClose(winevtSubscribe->event);
+ for (int i = 0; i < winevtSubscribe->count; i++) {
+ if (winevtSubscribe->hEvents[i]) {
+ EvtClose(winevtSubscribe->hEvents[i]);
+ }
+ }
xfree(ptr);
}
static VALUE
rb_winevt_subscribe_alloc(VALUE klass)
{
VALUE obj;
- struct WinevtSubscribe *winevtSubscribe;
- obj = TypedData_Make_Struct(klass,
- struct WinevtSubscribe,
- &rb_winevt_subscribe_type,
- winevtSubscribe);
+ struct WinevtSubscribe* winevtSubscribe;
+ obj = TypedData_Make_Struct(
+ klass, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
return obj;
}
static VALUE
rb_winevt_subscribe_initialize(VALUE self)
{
+ struct WinevtSubscribe* winevtSubscribe;
+
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+
+ winevtSubscribe->rateLimit = SUBSCRIBE_RATE_INFINITE;
+ winevtSubscribe->lastTime = 0;
+ winevtSubscribe->currentRate = 0;
+ winevtSubscribe->renderAsXML = TRUE;
+
return Qnil;
}
static VALUE
rb_winevt_subscribe_set_tail(VALUE self, VALUE rb_tailing_p)
{
- struct WinevtSubscribe *winevtSubscribe;
+ struct WinevtSubscribe* winevtSubscribe;
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
winevtSubscribe->tailing = RTEST(rb_tailing_p);
return Qnil;
}
static VALUE
rb_winevt_subscribe_tail_p(VALUE self, VALUE rb_flag)
{
- struct WinevtSubscribe *winevtSubscribe;
+ struct WinevtSubscribe* winevtSubscribe;
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
return winevtSubscribe->tailing ? Qtrue : Qfalse;
}
static VALUE
-rb_winevt_subscribe_subscribe(int argc, VALUE *argv, VALUE self)
+rb_winevt_subscribe_subscribe(int argc, VALUE* argv, VALUE self)
{
VALUE rb_path, rb_query, rb_bookmark;
EVT_HANDLE hSubscription = NULL, hBookmark = NULL;
HANDLE hSignalEvent;
DWORD len, flags = 0L;
VALUE wpathBuf, wqueryBuf;
PWSTR path, query;
DWORD status = ERROR_SUCCESS;
- struct WinevtSubscribe *winevtSubscribe;
+ struct WinevtSubscribe* winevtSubscribe;
hSignalEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
rb_scan_args(argc, argv, "21", &rb_path, &rb_query, &rb_bookmark);
Check_Type(rb_path, T_STRING);
Check_Type(rb_query, T_STRING);
if (rb_obj_is_kind_of(rb_bookmark, rb_cBookmark)) {
hBookmark = EventBookMark(rb_bookmark)->bookmark;
}
// path : To wide char
- len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_path), RSTRING_LEN(rb_path), NULL, 0);
- path = ALLOCV_N(WCHAR, wpathBuf, len+1);
+ len =
+ MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_path), RSTRING_LEN(rb_path), NULL, 0);
+ path = ALLOCV_N(WCHAR, wpathBuf, len + 1);
MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_path), RSTRING_LEN(rb_path), path, len);
path[len] = L'\0';
// query : To wide char
- len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_query), RSTRING_LEN(rb_query), NULL, 0);
- query = ALLOCV_N(WCHAR, wqueryBuf, len+1);
- MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_query), RSTRING_LEN(rb_query), query, len);
+ len = MultiByteToWideChar(
+ CP_UTF8, 0, RSTRING_PTR(rb_query), RSTRING_LEN(rb_query), NULL, 0);
+ query = ALLOCV_N(WCHAR, wqueryBuf, len + 1);
+ MultiByteToWideChar(
+ CP_UTF8, 0, RSTRING_PTR(rb_query), RSTRING_LEN(rb_query), query, len);
query[len] = L'\0';
- if (hBookmark){
+ if (hBookmark) {
flags |= EvtSubscribeStartAfterBookmark;
} else if (winevtSubscribe->tailing) {
flags |= EvtSubscribeToFutureEvents;
} else {
flags |= EvtSubscribeStartAtOldestRecord;
}
- hSubscription = EvtSubscribe(NULL, hSignalEvent, path, query, hBookmark, NULL, NULL, flags);
+ hSubscription =
+ EvtSubscribe(NULL, hSignalEvent, path, query, hBookmark, NULL, NULL, flags);
ALLOCV_END(wpathBuf);
ALLOCV_END(wqueryBuf);
winevtSubscribe->signalEvent = hSignalEvent;
@@ -131,146 +152,250 @@
return Qtrue;
return Qfalse;
}
+BOOL
+is_rate_limit_exceeded(struct WinevtSubscribe *winevtSubscribe)
+{
+ time_t now;
+
+ if (winevtSubscribe->rateLimit == SUBSCRIBE_RATE_INFINITE)
+ return FALSE;
+
+ time(&now);
+
+ if (now <= winevtSubscribe->lastTime) {
+ if (winevtSubscribe->currentRate >= winevtSubscribe->rateLimit) {
+ return TRUE;
+ }
+ } else {
+ winevtSubscribe->currentRate = 0;
+ }
+
+ return FALSE;
+}
+
+void
+update_to_reflect_rate_limit_state(struct WinevtSubscribe *winevtSubscribe, ULONG count)
+{
+ time_t lastTime = 0;
+
+ if (winevtSubscribe->rateLimit == SUBSCRIBE_RATE_INFINITE)
+ return;
+
+ time(&lastTime);
+ winevtSubscribe->lastTime = lastTime;
+ winevtSubscribe->currentRate += count;
+}
+
static VALUE
rb_winevt_subscribe_next(VALUE self)
{
- EVT_HANDLE event;
- ULONG count;
- struct WinevtSubscribe *winevtSubscribe;
+ EVT_HANDLE hEvents[SUBSCRIBE_ARRAY_SIZE];
+ ULONG count = 0;
+ DWORD status = ERROR_SUCCESS;
+ struct WinevtSubscribe* winevtSubscribe;
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
- if (EvtNext(winevtSubscribe->subscription, 1, &event, INFINITE, 0, &count) != FALSE) {
- winevtSubscribe->event = event;
- EvtUpdateBookmark(winevtSubscribe->bookmark, winevtSubscribe->event);
+ if (is_rate_limit_exceeded(winevtSubscribe)) {
+ return Qfalse;
+ }
+ if (!EvtNext(winevtSubscribe->subscription, SUBSCRIBE_ARRAY_SIZE,
+ hEvents, INFINITE, 0, &count)) {
+ status = GetLastError();
+ if (ERROR_NO_MORE_ITEMS != status) {
+ return Qfalse;
+ }
+ }
+
+ if (status == ERROR_SUCCESS) {
+ winevtSubscribe->count = count;
+ for (int i = 0; i < count; i++) {
+ winevtSubscribe->hEvents[i] = hEvents[i];
+ EvtUpdateBookmark(winevtSubscribe->bookmark, winevtSubscribe->hEvents[i]);
+ }
+
+ update_to_reflect_rate_limit_state(winevtSubscribe, count);
+
return Qtrue;
}
return Qfalse;
}
static VALUE
-rb_winevt_subscribe_render(VALUE self)
+rb_winevt_subscribe_render(VALUE self, EVT_HANDLE event)
{
- WCHAR* wResult;
- struct WinevtSubscribe *winevtSubscribe;
- VALUE utf8str;
+ struct WinevtSubscribe* winevtSubscribe;
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
- wResult = render_event(winevtSubscribe->event, EvtRenderEventXml);
- utf8str = wstr_to_rb_str(CP_UTF8, wResult, -1);
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
- if (wResult != NULL)
- free(wResult);
-
- return utf8str;
+ if (winevtSubscribe->renderAsXML) {
+ return render_to_rb_str(event, EvtRenderEventXml);
+ } else {
+ return render_system_event(event);
+ }
}
static VALUE
-rb_winevt_subscribe_message(VALUE self)
+rb_winevt_subscribe_message(EVT_HANDLE event)
{
WCHAR* wResult;
- struct WinevtSubscribe *winevtSubscribe;
VALUE utf8str;
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
- wResult = get_description(winevtSubscribe->event);
+ wResult = get_description(event);
utf8str = wstr_to_rb_str(CP_UTF8, wResult, -1);
+ free(wResult);
- if (wResult != NULL)
- free(wResult);
-
return utf8str;
}
static VALUE
-rb_winevt_subscribe_string_inserts(VALUE self)
+rb_winevt_subscribe_string_inserts(EVT_HANDLE event)
{
- struct WinevtSubscribe *winevtSubscribe;
-
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
- return get_values(winevtSubscribe->event);
+ return get_values(event);
}
static VALUE
rb_winevt_subscribe_close_handle(VALUE self)
{
- struct WinevtSubscribe *winevtSubscribe;
+ struct WinevtSubscribe* winevtSubscribe;
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
- if (winevtSubscribe->event != NULL) {
- EvtClose(winevtSubscribe->event);
+ for (int i = 0; i < winevtSubscribe->count; i++) {
+ if (winevtSubscribe->hEvents[i] != NULL) {
+ EvtClose(winevtSubscribe->hEvents[i]);
+ winevtSubscribe->hEvents[i] = NULL;
+ }
}
return Qnil;
}
static VALUE
rb_winevt_subscribe_each_yield(VALUE self)
{
- struct WinevtSubscribe *winevtSubscribe;
-
RETURN_ENUMERATOR(self, 0, 0);
+ struct WinevtSubscribe* winevtSubscribe;
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
- rb_yield_values(3,
- rb_winevt_subscribe_render(self),
- rb_winevt_subscribe_message(self),
- rb_winevt_subscribe_string_inserts(self));
+ for (int i = 0; i < winevtSubscribe->count; i++) {
+ rb_yield_values(3,
+ rb_winevt_subscribe_render(self, winevtSubscribe->hEvents[i]),
+ rb_winevt_subscribe_message(winevtSubscribe->hEvents[i]),
+ rb_winevt_subscribe_string_inserts(winevtSubscribe->hEvents[i]));
+ }
return Qnil;
}
static VALUE
rb_winevt_subscribe_each(VALUE self)
{
- struct WinevtSubscribe *winevtSubscribe;
-
RETURN_ENUMERATOR(self, 0, 0);
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
-
while (rb_winevt_subscribe_next(self)) {
- rb_ensure(rb_winevt_subscribe_each_yield, self, rb_winevt_subscribe_close_handle, self);
+ rb_ensure(
+ rb_winevt_subscribe_each_yield, self, rb_winevt_subscribe_close_handle, self);
}
return Qnil;
}
static VALUE
rb_winevt_subscribe_get_bookmark(VALUE self)
{
- WCHAR* wResult;
- struct WinevtSubscribe *winevtSubscribe;
- VALUE utf8str;
+ struct WinevtSubscribe* winevtSubscribe;
- TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
- wResult = render_event(winevtSubscribe->bookmark, EvtRenderBookmark);
- utf8str = wstr_to_rb_str(CP_UTF8, wResult, -1);
+ return render_to_rb_str(winevtSubscribe->bookmark, EvtRenderBookmark);
+}
- return utf8str;
+static VALUE
+rb_winevt_subscribe_get_rate_limit(VALUE self)
+{
+ struct WinevtSubscribe* winevtSubscribe;
+
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+
+ return INT2NUM(winevtSubscribe->rateLimit);
}
-void Init_winevt_subscribe(VALUE rb_cEventLog)
+static VALUE
+rb_winevt_subscribe_set_rate_limit(VALUE self, VALUE rb_rate_limit)
{
+ struct WinevtSubscribe* winevtSubscribe;
+ DWORD rateLimit;
+
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+
+ rateLimit = NUM2LONG(rb_rate_limit);
+
+ if ((rateLimit != SUBSCRIBE_RATE_INFINITE) &&
+ (rateLimit < 10 || rateLimit % 10)) {
+ rb_raise(rb_eArgError,
+ "Specify a multiples of 10 or RATE_INFINITE constant");
+ } else {
+ winevtSubscribe->rateLimit = rateLimit;
+ }
+
+ return Qnil;
+}
+
+static VALUE
+rb_winevt_subscribe_render_as_xml_p(VALUE self)
+{
+ struct WinevtSubscribe* winevtSubscribe;
+
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+
+ return winevtSubscribe->renderAsXML ? Qtrue : Qfalse;
+}
+
+static VALUE
+rb_winevt_subscribe_set_render_as_xml(VALUE self, VALUE rb_render_as_xml)
+{
+ struct WinevtSubscribe* winevtSubscribe;
+
+ TypedData_Get_Struct(
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
+
+ winevtSubscribe->renderAsXML = RTEST(rb_render_as_xml);
+
+ return Qnil;
+}
+
+void
+Init_winevt_subscribe(VALUE rb_cEventLog)
+{
rb_cSubscribe = rb_define_class_under(rb_cEventLog, "Subscribe", rb_cObject);
rb_define_alloc_func(rb_cSubscribe, rb_winevt_subscribe_alloc);
+
+ rb_define_const(rb_cSubscribe, "RATE_INFINITE", SUBSCRIBE_RATE_INFINITE);
+
rb_define_method(rb_cSubscribe, "initialize", rb_winevt_subscribe_initialize, 0);
rb_define_method(rb_cSubscribe, "subscribe", rb_winevt_subscribe_subscribe, -1);
rb_define_method(rb_cSubscribe, "next", rb_winevt_subscribe_next, 0);
- rb_define_method(rb_cSubscribe, "render", rb_winevt_subscribe_render, 0);
- rb_define_method(rb_cSubscribe, "message", rb_winevt_subscribe_message, 0);
- rb_define_method(rb_cSubscribe, "string_inserts", rb_winevt_subscribe_string_inserts, 0);
rb_define_method(rb_cSubscribe, "each", rb_winevt_subscribe_each, 0);
- rb_define_method(rb_cSubscribe, "close_handle", rb_winevt_subscribe_close_handle, 0);
rb_define_method(rb_cSubscribe, "bookmark", rb_winevt_subscribe_get_bookmark, 0);
rb_define_method(rb_cSubscribe, "tail?", rb_winevt_subscribe_tail_p, 0);
rb_define_method(rb_cSubscribe, "tail=", rb_winevt_subscribe_set_tail, 1);
+ rb_define_method(rb_cSubscribe, "rate_limit", rb_winevt_subscribe_get_rate_limit, 0);
+ rb_define_method(rb_cSubscribe, "rate_limit=", rb_winevt_subscribe_set_rate_limit, 1);
+ rb_define_method(rb_cSubscribe, "render_as_xml?", rb_winevt_subscribe_render_as_xml_p, 0);
+ rb_define_method(rb_cSubscribe, "render_as_xml=", rb_winevt_subscribe_set_render_as_xml, 1);
}