god 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|