1 #ifdef __linux__ /* only build on linux */
6 #include <sys/socket.h>
7 #include <linux/netlink.h>
8 #include <linux/connector.h>
9 #include <linux/cn_proc.h>
13 static VALUE cNetlinkHandler
;
14 static VALUE cEventHandler
;
19 static ID m_watching_pid
;
21 static int nl_sock
; /* socket for netlink connection */
27 char buff
[CONNECTOR_MAX_MSG_SIZE
];
29 struct proc_event
*event
;
36 FD_SET(nl_sock
, &fds
);
38 if (0 > rb_thread_select(nl_sock
+ 1, &fds
, NULL
, NULL
, NULL
)) {
39 rb_raise(rb_eStandardError
, strerror(errno
));
42 /* If there were no events detected, return */
43 if (! FD_ISSET(nl_sock
, &fds
)) {
47 /* if there are events, make calls */
48 if (-1 == recv(nl_sock
, buff
, sizeof(buff
), 0)) {
49 rb_raise(rb_eStandardError
, strerror(errno
));
52 hdr
= (struct nlmsghdr
*)buff
;
54 if (NLMSG_ERROR
== hdr
->nlmsg_type
) {
55 rb_raise(rb_eStandardError
, strerror(errno
));
56 } else if (NLMSG_DONE
== hdr
->nlmsg_type
) {
58 event
= (struct proc_event
*)((struct cn_msg
*)NLMSG_DATA(hdr
))->data
;
62 if (Qnil
== rb_funcall(cEventHandler
, m_watching_pid
, 1, INT2FIX(event
->event_data
.exit
.process_pid
))) {
66 extra_data
= rb_hash_new();
67 rb_hash_aset(extra_data
, ID2SYM(rb_intern("exit_code")), INT2FIX(event
->event_data
.exit
.exit_code
));
68 rb_hash_aset(extra_data
, ID2SYM(rb_intern("exit_signal")), INT2FIX(event
->event_data
.exit
.exit_signal
));
69 rb_hash_aset(extra_data
, ID2SYM(rb_intern("thread_group_id")), INT2FIX(event
->event_data
.exit
.process_tgid
));
71 rb_funcall(cEventHandler
, m_call
, 3, INT2FIX(event
->event_data
.exit
.process_pid
), ID2SYM(proc_exit
), extra_data
);
75 if (Qnil
== rb_funcall(cEventHandler
, m_watching_pid
, 1, INT2FIX(event
->event_data
.fork
.parent_pid
))) {
79 extra_data
= rb_hash_new();
80 rb_hash_aset(extra_data
, rb_intern("parent_thread_group_id"), INT2FIX(event
->event_data
.fork
.parent_tgid
));
81 rb_hash_aset(extra_data
, rb_intern("child_pid"), INT2FIX(event
->event_data
.fork
.child_pid
));
82 rb_hash_aset(extra_data
, rb_intern("child_thread_group_id"), INT2FIX(event
->event_data
.fork
.child_tgid
));
84 rb_funcall(cEventHandler
, m_call
, 3, INT2FIX(event
->event_data
.fork
.parent_pid
), ID2SYM(proc_fork
), extra_data
);
99 #define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \
105 struct sockaddr_nl sa_nl
; /* netlink interface info */
106 char buff
[NL_MESSAGE_SIZE
];
107 struct nlmsghdr
*hdr
; /* for telling netlink what we want */
108 struct cn_msg
*msg
; /* the actual connector message */
110 /* connect to netlink socket */
111 nl_sock
= socket(PF_NETLINK
, SOCK_DGRAM
, NETLINK_CONNECTOR
);
114 rb_raise(rb_eStandardError
, strerror(errno
));
117 bzero(&sa_nl
, sizeof(sa_nl
));
118 sa_nl
.nl_family
= AF_NETLINK
;
119 sa_nl
.nl_groups
= CN_IDX_PROC
;
120 sa_nl
.nl_pid
= getpid();
122 if (-1 == bind(nl_sock
, (struct sockaddr
*)&sa_nl
, sizeof(sa_nl
))) {
123 rb_raise(rb_eStandardError
, strerror(errno
));
127 hdr
= (struct nlmsghdr
*)buff
;
128 hdr
->nlmsg_len
= NL_MESSAGE_SIZE
;
129 hdr
->nlmsg_type
= NLMSG_DONE
;
130 hdr
->nlmsg_flags
= 0;
132 hdr
->nlmsg_pid
= getpid();
135 msg
= (struct cn_msg
*)NLMSG_DATA(hdr
);
136 msg
->id
.idx
= CN_IDX_PROC
; /* Connecting to process information */
137 msg
->id
.val
= CN_VAL_PROC
;
141 msg
->len
= sizeof(int);
142 *(int*)msg
->data
= PROC_CN_MCAST_LISTEN
;
144 if (-1 == send(nl_sock
, hdr
, hdr
->nlmsg_len
, 0)) {
145 rb_raise(rb_eStandardError
, strerror(errno
));
150 Init_netlink_handler_ext()
152 proc_exit
= rb_intern("proc_exit");
153 proc_fork
= rb_intern("proc_fork");
154 m_call
= rb_intern("call");
155 m_watching_pid
= rb_intern("watching_pid?");
157 mGod
= rb_const_get(rb_cObject
, rb_intern("God"));
158 cEventHandler
= rb_const_get(mGod
, rb_intern("EventHandler"));
159 cNetlinkHandler
= rb_define_class_under(mGod
, "NetlinkHandler", rb_cObject
);
160 rb_define_singleton_method(cNetlinkHandler
, "handle_events", nlh_handle_events
, 0);
162 connect_to_netlink();