fix flapping for simple mode configs, more test coverage
[god.git] / ext / god / netlink_handler.c
blobeca5b0e589c67e94c3720972277decba47b41e99
1 #ifdef __linux__ /* only build on linux */
3 #include <ruby.h>
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <sys/socket.h>
7 #include <linux/netlink.h>
8 #include <linux/connector.h>
9 #include <linux/cn_proc.h>
10 #include <errno.h>
12 static VALUE mGod;
13 static VALUE cNetlinkHandler;
14 static VALUE cEventHandler;
16 static ID proc_exit;
17 static ID proc_fork;
18 static ID m_call;
19 static ID m_watching_pid;
21 static int nl_sock; /* socket for netlink connection */
24 VALUE
25 nlh_handle_events()
27 char buff[CONNECTOR_MAX_MSG_SIZE];
28 struct nlmsghdr *hdr;
29 struct proc_event *event;
31 fd_set fds;
33 FD_ZERO(&fds);
34 FD_SET(nl_sock, &fds);
36 if (0 > rb_thread_select(nl_sock + 1, &fds, NULL, NULL, NULL)) {
37 rb_raise(rb_eStandardError, strerror(errno));
40 /* If there were no events detected, return */
41 if (! FD_ISSET(nl_sock, &fds)) {
42 return INT2FIX(0);
45 /* if there are events, make calls */
46 if (-1 == recv(nl_sock, buff, sizeof(buff), 0)) {
47 rb_raise(rb_eStandardError, strerror(errno));
50 hdr = (struct nlmsghdr *)buff;
52 if (NLMSG_ERROR == hdr->nlmsg_type) {
53 rb_raise(rb_eStandardError, strerror(errno));
54 } else if (NLMSG_DONE == hdr->nlmsg_type) {
56 event = (struct proc_event *)((struct cn_msg *)NLMSG_DATA(hdr))->data;
58 switch(event->what) {
59 case PROC_EVENT_EXIT:
60 if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.exit.process_pid))) {
61 return INT2FIX(0);
64 rb_funcall(cEventHandler, m_call, 2, INT2FIX(event->event_data.exit.process_pid), ID2SYM(proc_exit));
65 return INT2FIX(1);
67 /* TODO: On fork, call and pass pid of child */
68 case PROC_EVENT_FORK:
69 if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.fork.parent_pid))) {
70 return INT2FIX(0);
73 rb_funcall(cEventHandler, m_call, 2, INT2FIX(event->event_data.fork.parent_pid), ID2SYM(proc_fork));
74 return INT2FIX(1);
76 case PROC_EVENT_NONE:
77 case PROC_EVENT_EXEC:
78 case PROC_EVENT_UID:
79 case PROC_EVENT_GID:
80 break;
84 return Qnil;
88 #define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \
89 sizeof(int))
91 void
92 connect_to_netlink()
94 struct sockaddr_nl sa_nl; /* netlink interface info */
95 char buff[NL_MESSAGE_SIZE];
96 struct nlmsghdr *hdr; /* for telling netlink what we want */
97 struct cn_msg *msg; /* the actual connector message */
99 /* connect to netlink socket */
100 nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
102 if (-1 == nl_sock) {
103 rb_raise(rb_eStandardError, strerror(errno));
106 bzero(&sa_nl, sizeof(sa_nl));
107 sa_nl.nl_family = AF_NETLINK;
108 sa_nl.nl_groups = CN_IDX_PROC;
109 sa_nl.nl_pid = getpid();
111 if (-1 == bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl))) {
112 rb_raise(rb_eStandardError, strerror(errno));
115 /* Fill header */
116 hdr = (struct nlmsghdr *)buff;
117 hdr->nlmsg_len = NL_MESSAGE_SIZE;
118 hdr->nlmsg_type = NLMSG_DONE;
119 hdr->nlmsg_flags = 0;
120 hdr->nlmsg_seq = 0;
121 hdr->nlmsg_pid = getpid();
123 /* Fill message */
124 msg = (struct cn_msg *)NLMSG_DATA(hdr);
125 msg->id.idx = CN_IDX_PROC; /* Connecting to process information */
126 msg->id.val = CN_VAL_PROC;
127 msg->seq = 0;
128 msg->ack = 0;
129 msg->len = sizeof(int);
130 msg->data[0] = PROC_CN_MCAST_LISTEN;
132 if (-1 == send(nl_sock, hdr, hdr->nlmsg_len, 0)) {
133 rb_raise(rb_eStandardError, strerror(errno));
137 void
138 Init_netlink_handler_ext()
140 proc_exit = rb_intern("proc_exit");
141 proc_fork = rb_intern("proc_fork");
142 m_call = rb_intern("call");
143 m_watching_pid = rb_intern("watching_pid?");
145 mGod = rb_const_get(rb_cObject, rb_intern("God"));
146 cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
147 cNetlinkHandler = rb_define_class_under(mGod, "NetlinkHandler", rb_cObject);
148 rb_define_singleton_method(cNetlinkHandler, "handle_events", nlh_handle_events, 0);
150 connect_to_netlink();
153 #endif