god 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -1
- data/Manifest.txt +13 -1
- data/README.txt +2 -0
- data/Rakefile +2 -2
- data/examples/gravatar.god +8 -2
- data/examples/local.god +4 -4
- data/ext/god/Makefile +149 -0
- data/ext/god/extconf.rb +8 -0
- data/ext/god/kqueue_handler.c +122 -0
- data/ext/god/netlink_handler.c +140 -0
- data/lib/god.rb +37 -4
- data/lib/god/conditions/always.rb +9 -1
- data/lib/god/conditions/cpu_usage.rb +2 -2
- data/lib/god/conditions/memory_usage.rb +2 -2
- data/lib/god/conditions/process_exits.rb +28 -0
- data/lib/god/conditions/process_running.rb +25 -0
- data/lib/god/event_handler.rb +45 -0
- data/lib/god/event_handlers/kqueue_handler.rb +15 -0
- data/lib/god/event_handlers/netlink_handler.rb +11 -0
- data/lib/god/hub.rb +84 -0
- data/lib/god/meddle.rb +1 -17
- data/lib/god/metric.rb +60 -0
- data/lib/god/timer.rb +21 -26
- data/lib/god/watch.rb +90 -58
- data/test/configs/real.rb +2 -5
- data/test/configs/test.rb +75 -0
- data/test/helper.rb +1 -0
- data/test/test_condition.rb +1 -1
- data/test/test_god.rb +3 -2
- data/test/test_metric.rb +60 -0
- data/test/test_timer.rb +21 -11
- data/test/test_watch.rb +49 -78
- metadata +20 -6
- data/lib/god/conditions/process_not_running.rb +0 -22
data/History.txt
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
==
|
1
|
+
== 0.2.0
|
2
|
+
|
3
|
+
* Rewrote innards to use a state and event based lifecycle
|
4
|
+
* Basic support for events via kqueue (bsd/darwin) and netlink/pec (linux) [kevinclark]
|
5
|
+
* Added advanced syntax (simple syntax calls advanced api underneath)
|
6
|
+
* Condition returns have changed meaning. With simple syntax, a true return activates block
|
7
|
+
* Updated http://god.rubygorge.org with updated simple config and new advanced config
|
8
|
+
|
9
|
+
== 0.1.0 / 2007-07-07
|
2
10
|
|
3
11
|
* 1 major enhancement
|
4
12
|
* Birthday!
|
data/Manifest.txt
CHANGED
@@ -5,6 +5,10 @@ Rakefile
|
|
5
5
|
bin/god
|
6
6
|
examples/gravatar.god
|
7
7
|
examples/local.god
|
8
|
+
ext/god/Makefile
|
9
|
+
ext/god/extconf.rb
|
10
|
+
ext/god/kqueue_handler.c
|
11
|
+
ext/god/netlink_handler.c
|
8
12
|
lib/god.rb
|
9
13
|
lib/god/base.rb
|
10
14
|
lib/god/behavior.rb
|
@@ -13,22 +17,30 @@ lib/god/condition.rb
|
|
13
17
|
lib/god/conditions/always.rb
|
14
18
|
lib/god/conditions/cpu_usage.rb
|
15
19
|
lib/god/conditions/memory_usage.rb
|
16
|
-
lib/god/conditions/
|
20
|
+
lib/god/conditions/process_exits.rb
|
21
|
+
lib/god/conditions/process_running.rb
|
17
22
|
lib/god/conditions/timeline.rb
|
18
23
|
lib/god/errors.rb
|
24
|
+
lib/god/event_handler.rb
|
25
|
+
lib/god/event_handlers/kqueue_handler.rb
|
26
|
+
lib/god/event_handlers/netlink_handler.rb
|
27
|
+
lib/god/hub.rb
|
19
28
|
lib/god/meddle.rb
|
29
|
+
lib/god/metric.rb
|
20
30
|
lib/god/reporter.rb
|
21
31
|
lib/god/server.rb
|
22
32
|
lib/god/system/process.rb
|
23
33
|
lib/god/timer.rb
|
24
34
|
lib/god/watch.rb
|
25
35
|
test/configs/real.rb
|
36
|
+
test/configs/test.rb
|
26
37
|
test/helper.rb
|
27
38
|
test/suite.rb
|
28
39
|
test/test_behavior.rb
|
29
40
|
test/test_condition.rb
|
30
41
|
test/test_god.rb
|
31
42
|
test/test_meddle.rb
|
43
|
+
test/test_metric.rb
|
32
44
|
test/test_reporter.rb
|
33
45
|
test/test_server.rb
|
34
46
|
test/test_system_process.rb
|
data/README.txt
CHANGED
data/Rakefile
CHANGED
@@ -2,9 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'hoe'
|
5
|
-
require './lib/god.rb'
|
6
5
|
|
7
|
-
Hoe.new('god',
|
6
|
+
Hoe.new('god', '0.2.0') do |p|
|
8
7
|
p.rubyforge_name = 'god'
|
9
8
|
p.author = 'Tom Preston-Werner'
|
10
9
|
p.email = 'tom@rubyisawesome.com'
|
@@ -13,6 +12,7 @@ Hoe.new('god', God::VERSION) do |p|
|
|
13
12
|
p.description = "God is an easy to configure, easy to extend monitoring framework written in Ruby."
|
14
13
|
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
14
|
p.extra_deps << ['daemons', '>=1.0.7']
|
15
|
+
p.spec_extras = {:extensions => ['ext/god/extconf.rb']}
|
16
16
|
end
|
17
17
|
|
18
18
|
desc "Open an irb session preloaded with this library"
|
data/examples/gravatar.god
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# run with: god start -c /path/to/gravatar.god
|
2
|
+
#
|
1
3
|
# This is the actual config file used to keep the mongrels of
|
2
4
|
# gravatar.com running.
|
3
5
|
|
@@ -8,8 +10,11 @@ God.meddle do |god|
|
|
8
10
|
god.watch do |w|
|
9
11
|
w.name = "gravatar2-mongrel-#{port}"
|
10
12
|
w.interval = 30 # seconds
|
11
|
-
w.start = "mongrel_rails cluster::start --only #{port}
|
12
|
-
|
13
|
+
w.start = "mongrel_rails cluster::start --only #{port} \
|
14
|
+
-C #{RAILS_ROOT}/config/mongrel_cluster.yml"
|
15
|
+
w.stop = "mongrel_rails cluster::stop --only #{port} \
|
16
|
+
-C #{RAILS_ROOT}/config/mongrel_cluster.yml"
|
17
|
+
w.grace = 10 # seconds
|
13
18
|
|
14
19
|
pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
|
15
20
|
|
@@ -19,6 +24,7 @@ God.meddle do |god|
|
|
19
24
|
|
20
25
|
w.start_if do |start|
|
21
26
|
start.condition(:process_not_running) do |c|
|
27
|
+
c.interval = 5 # seconds
|
22
28
|
c.pid_file = pid_file
|
23
29
|
end
|
24
30
|
end
|
data/examples/local.god
CHANGED
@@ -2,15 +2,14 @@
|
|
2
2
|
# and running on your Mac.
|
3
3
|
|
4
4
|
# Run with:
|
5
|
-
# god local.god
|
5
|
+
# god start -c /path/to/local.god
|
6
6
|
|
7
7
|
RAILS_ROOT = "/Users/tom/dev/powerset/querytopia"
|
8
8
|
|
9
9
|
God.meddle do |god|
|
10
|
-
god.interval = 5 # seconds
|
11
|
-
|
12
10
|
god.watch do |w|
|
13
11
|
w.name = "local-3000"
|
12
|
+
w.interval = 5 # seconds
|
14
13
|
w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d"
|
15
14
|
w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
|
16
15
|
w.grace = 5
|
@@ -24,7 +23,7 @@ God.meddle do |god|
|
|
24
23
|
|
25
24
|
# start if process is not running
|
26
25
|
w.start_if do |start|
|
27
|
-
start.condition(:
|
26
|
+
start.condition(:process_exits) do |c|
|
28
27
|
c.pid_file = pid_file
|
29
28
|
end
|
30
29
|
end
|
@@ -48,6 +47,7 @@ God.meddle do |god|
|
|
48
47
|
# clear old session files
|
49
48
|
god.watch do |w|
|
50
49
|
w.name = "local-session-cleanup"
|
50
|
+
w.interval = 60 # seconds
|
51
51
|
w.cwd = File.join(RAILS_ROOT, 'tmp/sessions')
|
52
52
|
w.start = lambda do
|
53
53
|
Dir['ruby_sess.*'].select { |f| File.mtime(f) < Time.now - (7 * 24 * 60 * 60) }.each { |f| File.delete(f) }
|
data/ext/god/Makefile
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /usr/local/lib/ruby/1.8/i686-darwin8.9.1
|
8
|
+
hdrdir = $(topdir)
|
9
|
+
VPATH = $(srcdir):$(topdir):$(hdrdir)
|
10
|
+
prefix = $(DESTDIR)/usr/local
|
11
|
+
exec_prefix = $(prefix)
|
12
|
+
sitedir = $(DESTDIR)/p/libdata/ruby
|
13
|
+
rubylibdir = $(libdir)/ruby/$(ruby_version)
|
14
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
15
|
+
dvidir = $(docdir)
|
16
|
+
datarootdir = $(prefix)/share
|
17
|
+
archdir = $(rubylibdir)/$(arch)
|
18
|
+
sbindir = $(exec_prefix)/sbin
|
19
|
+
psdir = $(docdir)
|
20
|
+
localedir = $(datarootdir)/locale
|
21
|
+
htmldir = $(docdir)
|
22
|
+
datadir = $(datarootdir)
|
23
|
+
includedir = $(prefix)/include
|
24
|
+
infodir = $(datarootdir)/info
|
25
|
+
sysconfdir = $(prefix)/etc
|
26
|
+
mandir = $(datarootdir)/man
|
27
|
+
libdir = $(exec_prefix)/lib
|
28
|
+
sharedstatedir = $(prefix)/com
|
29
|
+
oldincludedir = $(DESTDIR)/usr/include
|
30
|
+
pdfdir = $(docdir)
|
31
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
32
|
+
bindir = $(exec_prefix)/bin
|
33
|
+
localstatedir = $(prefix)/var
|
34
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
35
|
+
libexecdir = $(exec_prefix)/libexec
|
36
|
+
|
37
|
+
CC = gcc
|
38
|
+
LIBRUBY = $(LIBRUBY_A)
|
39
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
40
|
+
LIBRUBYARG_SHARED =
|
41
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
42
|
+
|
43
|
+
RUBY_EXTCONF_H =
|
44
|
+
CFLAGS = -fno-common -g -O2 -pipe -fno-common
|
45
|
+
INCFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir)
|
46
|
+
CPPFLAGS =
|
47
|
+
CXXFLAGS = $(CFLAGS)
|
48
|
+
DLDFLAGS =
|
49
|
+
LDSHARED = cc -dynamic -bundle -undefined suppress -flat_namespace
|
50
|
+
AR = ar
|
51
|
+
EXEEXT =
|
52
|
+
|
53
|
+
RUBY_INSTALL_NAME = ruby
|
54
|
+
RUBY_SO_NAME = ruby
|
55
|
+
arch = i686-darwin8.9.1
|
56
|
+
sitearch = i686-darwin8.9.1
|
57
|
+
ruby_version = 1.8
|
58
|
+
ruby = /usr/local/bin/ruby
|
59
|
+
RUBY = $(ruby)
|
60
|
+
RM = rm -f
|
61
|
+
MAKEDIRS = mkdir -p
|
62
|
+
INSTALL = /usr/bin/install -c
|
63
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
64
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
65
|
+
COPY = cp
|
66
|
+
|
67
|
+
#### End of system configuration section. ####
|
68
|
+
|
69
|
+
preload =
|
70
|
+
|
71
|
+
libpath = $(libdir)
|
72
|
+
LIBPATH = -L"$(libdir)"
|
73
|
+
DEFFILE =
|
74
|
+
|
75
|
+
CLEANFILES =
|
76
|
+
DISTCLEANFILES =
|
77
|
+
|
78
|
+
extout =
|
79
|
+
extout_prefix =
|
80
|
+
target_prefix =
|
81
|
+
LOCAL_LIBS =
|
82
|
+
LIBS = -lpthread -ldl -lobjc
|
83
|
+
SRCS = kqueue_handler.c netlink_handler.c
|
84
|
+
OBJS = kqueue_handler.o netlink_handler.o
|
85
|
+
TARGET = kqueue_handler_ext
|
86
|
+
DLLIB = $(TARGET).bundle
|
87
|
+
EXTSTATIC =
|
88
|
+
STATIC_LIB =
|
89
|
+
|
90
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
91
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
92
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
93
|
+
|
94
|
+
TARGET_SO = $(DLLIB)
|
95
|
+
CLEANLIBS = $(TARGET).bundle $(TARGET).il? $(TARGET).tds $(TARGET).map
|
96
|
+
CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
|
97
|
+
|
98
|
+
all: $(DLLIB)
|
99
|
+
static: $(STATIC_LIB)
|
100
|
+
|
101
|
+
clean:
|
102
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
103
|
+
|
104
|
+
distclean: clean
|
105
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
106
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
107
|
+
|
108
|
+
realclean: distclean
|
109
|
+
install: install-so install-rb
|
110
|
+
|
111
|
+
install-so: $(RUBYARCHDIR)
|
112
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
113
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
114
|
+
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
115
|
+
install-rb: pre-install-rb install-rb-default
|
116
|
+
install-rb-default: pre-install-rb-default
|
117
|
+
pre-install-rb: Makefile
|
118
|
+
pre-install-rb-default: Makefile
|
119
|
+
$(RUBYARCHDIR):
|
120
|
+
$(MAKEDIRS) $@
|
121
|
+
|
122
|
+
site-install: site-install-so site-install-rb
|
123
|
+
site-install-so: install-so
|
124
|
+
site-install-rb: install-rb
|
125
|
+
|
126
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
127
|
+
|
128
|
+
.cc.o:
|
129
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
130
|
+
|
131
|
+
.cxx.o:
|
132
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
133
|
+
|
134
|
+
.cpp.o:
|
135
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
136
|
+
|
137
|
+
.C.o:
|
138
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
139
|
+
|
140
|
+
.c.o:
|
141
|
+
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<
|
142
|
+
|
143
|
+
$(DLLIB): $(OBJS)
|
144
|
+
@-$(RM) $@
|
145
|
+
$(LDSHARED) $(DLDFLAGS) $(LIBPATH) -o $@ $(OBJS) $(LOCAL_LIBS) $(LIBS)
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
$(OBJS): ruby.h defines.h
|
data/ext/god/extconf.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
#if defined(__FreeBSD__) || defined(__APPLE__)
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
#include <sys/event.h>
|
5
|
+
#include <sys/time.h>
|
6
|
+
#include <errno.h>
|
7
|
+
|
8
|
+
static VALUE cKQueueHandler;
|
9
|
+
static VALUE cEventHandler;
|
10
|
+
static VALUE mGod;
|
11
|
+
|
12
|
+
static ID proc_exit;
|
13
|
+
static ID proc_fork;
|
14
|
+
static ID m_call;
|
15
|
+
static ID m_size;
|
16
|
+
static ID m_deregister;
|
17
|
+
|
18
|
+
static int kq;
|
19
|
+
int num_events;
|
20
|
+
|
21
|
+
#define NUM_EVENTS FIX2INT(rb_funcall(rb_cv_get(cEventHandler, "@@actions"), m_size, 0))
|
22
|
+
|
23
|
+
VALUE
|
24
|
+
kqh_event_mask(VALUE klass, VALUE sym)
|
25
|
+
{
|
26
|
+
ID id = SYM2ID(sym);
|
27
|
+
if (proc_exit == id) {
|
28
|
+
return UINT2NUM(NOTE_EXIT);
|
29
|
+
} else if (proc_fork == id) {
|
30
|
+
return UINT2NUM(NOTE_FORK);
|
31
|
+
} else {
|
32
|
+
rb_raise(rb_eNotImpError, "Event `%s` not implemented", rb_id2name(id));
|
33
|
+
}
|
34
|
+
|
35
|
+
return Qnil;
|
36
|
+
}
|
37
|
+
|
38
|
+
|
39
|
+
VALUE
|
40
|
+
kqh_monitor_process(VALUE klass, VALUE pid, VALUE mask)
|
41
|
+
{
|
42
|
+
struct kevent new_event;
|
43
|
+
ID event;
|
44
|
+
|
45
|
+
u_int fflags = NUM2UINT(mask);
|
46
|
+
|
47
|
+
EV_SET(&new_event, FIX2UINT(pid), EVFILT_PROC,
|
48
|
+
EV_ADD | EV_ENABLE, fflags, 0, 0);
|
49
|
+
|
50
|
+
if (-1 == kevent(kq, &new_event, 1, NULL, 0, NULL)) {
|
51
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
52
|
+
}
|
53
|
+
|
54
|
+
num_events = NUM_EVENTS;
|
55
|
+
|
56
|
+
return Qnil;
|
57
|
+
}
|
58
|
+
|
59
|
+
VALUE
|
60
|
+
kqh_handle_events()
|
61
|
+
{
|
62
|
+
int nevents, i, num_to_fetch;
|
63
|
+
struct kevent *events;
|
64
|
+
fd_set read_set;
|
65
|
+
|
66
|
+
FD_ZERO(&read_set);
|
67
|
+
FD_SET(kq, &read_set);
|
68
|
+
|
69
|
+
// Don't actually run this method until we've got an event
|
70
|
+
rb_thread_select(kq + 1, &read_set, NULL, NULL, NULL);
|
71
|
+
|
72
|
+
// Grabbing num_events once for thread safety
|
73
|
+
num_to_fetch = num_events;
|
74
|
+
events = (struct kevent*)malloc(num_to_fetch * sizeof(struct kevent));
|
75
|
+
|
76
|
+
if (NULL == events) {
|
77
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
78
|
+
}
|
79
|
+
|
80
|
+
nevents = kevent(kq, NULL, 0, events, num_to_fetch, NULL);
|
81
|
+
|
82
|
+
if (-1 == nevents) {
|
83
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
84
|
+
} else {
|
85
|
+
for (i = 0; i < nevents; i++) {
|
86
|
+
if (events[i].fflags & NOTE_EXIT) {
|
87
|
+
rb_funcall(cEventHandler, m_call, 2, INT2NUM(events[i].ident), ID2SYM(proc_exit));
|
88
|
+
} else if (events[i].fflags & NOTE_FORK) {
|
89
|
+
rb_funcall(cEventHandler, m_call, 2, INT2NUM(events[i].ident), ID2SYM(proc_fork));
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
free(events);
|
95
|
+
|
96
|
+
return INT2FIX(nevents);
|
97
|
+
}
|
98
|
+
|
99
|
+
void
|
100
|
+
Init_kqueue_handler_ext()
|
101
|
+
{
|
102
|
+
kq = kqueue();
|
103
|
+
|
104
|
+
if (kq == -1) {
|
105
|
+
rb_raise(rb_eStandardError, "kqueue initilization failed");
|
106
|
+
}
|
107
|
+
|
108
|
+
proc_exit = rb_intern("proc_exit");
|
109
|
+
proc_fork = rb_intern("proc_fork");
|
110
|
+
m_call = rb_intern("call");
|
111
|
+
m_size = rb_intern("size");
|
112
|
+
m_deregister = rb_intern("deregister");
|
113
|
+
|
114
|
+
mGod = rb_const_get(rb_cObject, rb_intern("God"));
|
115
|
+
cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
|
116
|
+
cKQueueHandler = rb_define_class_under(mGod, "KQueueHandler", rb_cObject);
|
117
|
+
rb_define_singleton_method(cKQueueHandler, "monitor_process", kqh_monitor_process, 2);
|
118
|
+
rb_define_singleton_method(cKQueueHandler, "handle_events", kqh_handle_events, 0);
|
119
|
+
rb_define_singleton_method(cKQueueHandler, "event_mask", kqh_event_mask, 1);
|
120
|
+
}
|
121
|
+
|
122
|
+
#endif
|
@@ -0,0 +1,140 @@
|
|
1
|
+
#ifdef __linux__ /* only build on linux */
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
#include <sys/types.h>
|
5
|
+
#include <sys/socket.h>
|
6
|
+
#include <linux/netlink.h>
|
7
|
+
#include <linux/connector.h>
|
8
|
+
#include <linux/cn_proc.h>
|
9
|
+
#include <errno.h>
|
10
|
+
|
11
|
+
static VALUE cNetlinkHandler;
|
12
|
+
static VALUE cEventHandler;
|
13
|
+
static VALUE mGod;
|
14
|
+
|
15
|
+
static ID proc_exit;
|
16
|
+
static ID proc_fork;
|
17
|
+
static ID m_call;
|
18
|
+
static ID m_watching_pid;
|
19
|
+
|
20
|
+
static int nl_sock; /* socket for netlink connection */
|
21
|
+
|
22
|
+
|
23
|
+
VALUE
|
24
|
+
nlh_handle_events()
|
25
|
+
{
|
26
|
+
char buff[CONNECTOR_MAX_MSG_SIZE];
|
27
|
+
struct nlmsghdr *hdr;
|
28
|
+
struct proc_event *event;
|
29
|
+
|
30
|
+
fd_set fds;
|
31
|
+
|
32
|
+
FD_ZERO(&fds);
|
33
|
+
FD_SET(nl_sock, &fds);
|
34
|
+
|
35
|
+
if (0 > rb_thread_select(nl_sock + 1, &fds, NULL, NULL, NULL)) {
|
36
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
37
|
+
}
|
38
|
+
|
39
|
+
/* If there were no events detected, return */
|
40
|
+
if (! FD_ISSET(nl_sock, &fds)) {
|
41
|
+
return INT2FIX(0);
|
42
|
+
}
|
43
|
+
|
44
|
+
/* if there are events, make calls */
|
45
|
+
if (-1 == recv(nl_sock, buff, sizeof(buff), 0)) {
|
46
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
47
|
+
}
|
48
|
+
|
49
|
+
hdr = (struct nlmsghdr *)buff;
|
50
|
+
|
51
|
+
if (NLMSG_ERROR == hdr->nlmsg_type) {
|
52
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
53
|
+
} else if (NLMSG_DONE == hdr->nlmsg_type) {
|
54
|
+
|
55
|
+
event = (struct proc_event *)((struct cn_msg *)NLMSG_DATA(hdr))->data;
|
56
|
+
|
57
|
+
switch(event->what) {
|
58
|
+
case PROC_EVENT_EXIT:
|
59
|
+
if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.exit.process_pid))) {
|
60
|
+
return INT2FIX(0);
|
61
|
+
}
|
62
|
+
|
63
|
+
rb_funcall(cEventHandler, m_call, 2, INT2FIX(event->event_data.exit.process_pid), ID2SYM(proc_exit));
|
64
|
+
return INT2FIX(1);
|
65
|
+
|
66
|
+
/* TODO: On fork, call and pass pid of child */
|
67
|
+
case PROC_EVENT_FORK:
|
68
|
+
if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.fork.parent_pid))) {
|
69
|
+
return INT2FIX(0);
|
70
|
+
}
|
71
|
+
|
72
|
+
rb_funcall(cEventHandler, m_call, 2, INT2FIX(event->event_data.fork.parent_pid), ID2SYM(proc_fork));
|
73
|
+
return INT2FIX(1);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
return Qnil;
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
#define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \
|
82
|
+
sizeof(int))
|
83
|
+
|
84
|
+
void
|
85
|
+
connect_to_netlink()
|
86
|
+
{
|
87
|
+
struct sockaddr_nl sa_nl; /* netlink interface info */
|
88
|
+
char buff[NL_MESSAGE_SIZE];
|
89
|
+
struct nlmsghdr *hdr; /* for telling netlink what we want */
|
90
|
+
struct cn_msg *msg; /* the actual connector message
|
91
|
+
|
92
|
+
/* connect to netlink socket */
|
93
|
+
nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
|
94
|
+
|
95
|
+
bzero(&sa_nl, sizeof(sa_nl));
|
96
|
+
sa_nl.nl_family = AF_NETLINK;
|
97
|
+
sa_nl.nl_groups = CN_IDX_PROC;
|
98
|
+
sa_nl.nl_pid = getpid();
|
99
|
+
|
100
|
+
bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
|
101
|
+
|
102
|
+
/* Fill header */
|
103
|
+
hdr = (struct nlmsghdr *)buff;
|
104
|
+
hdr->nlmsg_len = NL_MESSAGE_SIZE;
|
105
|
+
hdr->nlmsg_type = NLMSG_DONE;
|
106
|
+
hdr->nlmsg_flags = 0;
|
107
|
+
hdr->nlmsg_seq = 0;
|
108
|
+
hdr->nlmsg_pid = getpid();
|
109
|
+
|
110
|
+
/* Fill message */
|
111
|
+
msg = (struct cn_msg *)NLMSG_DATA(hdr);
|
112
|
+
msg->id.idx = CN_IDX_PROC; /* Connecting to process information */
|
113
|
+
msg->id.val = CN_VAL_PROC;
|
114
|
+
msg->seq = 0;
|
115
|
+
msg->ack = 0;
|
116
|
+
msg->len = sizeof(int);
|
117
|
+
msg->data[0] = PROC_CN_MCAST_LISTEN;
|
118
|
+
|
119
|
+
if (-1 == send(nl_sock, hdr, hdr->nlmsg_len, 0)) {
|
120
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
void
|
125
|
+
Init_netlink_handler_ext()
|
126
|
+
{
|
127
|
+
proc_exit = rb_intern("proc_exit");
|
128
|
+
proc_fork = rb_intern("proc_fork");
|
129
|
+
m_call = rb_intern("call");
|
130
|
+
m_watching_pid = rb_intern("watching_pid?");
|
131
|
+
|
132
|
+
mGod = rb_const_get(rb_cObject, rb_intern("God"));
|
133
|
+
cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
|
134
|
+
cNetlinkHandler = rb_define_class_under(mGod, "NetlinkHandler", rb_cObject);
|
135
|
+
rb_define_singleton_method(cNetlinkHandler, "handle_events", nlh_handle_events, 0);
|
136
|
+
|
137
|
+
connect_to_netlink();
|
138
|
+
}
|
139
|
+
|
140
|
+
#endif
|