Reorg for packaging
[god.git] / ext / god / netlink_handler.c
blob579d63f7155037ac73a66ca0b3b4a82faaa341c4
1 #ifdef __linux__ /* only build on linux */
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>
11 static VALUE cNetlinkHandler;
12 static VALUE cEventHandler;
13 static VALUE mGod;
15 static ID proc_exit;
16 static ID proc_fork;
17 static ID m_call;
18 static ID m_watching_pid;
20 static int nl_sock; /* socket for netlink connection */
23 VALUE
24 nlh_handle_events()
26 char buff[CONNECTOR_MAX_MSG_SIZE];
27 struct nlmsghdr *hdr;
28 struct proc_event *event;
30 fd_set fds;
32 FD_ZERO(&fds);
33 FD_SET(nl_sock, &fds);
35 if (0 > select(nl_sock + 1, &fds, NULL, NULL, NULL)) {
36 rb_raise(rb_eStandardError, strerror(errno));
39 /* If there were no events detected, return */
40 if (! FD_ISSET(nl_sock, &fds)) {
41 return INT2FIX(0);
44 /* if there are events, make calls */
45 if (-1 == recv(nl_sock, buff, sizeof(buff), 0)) {
46 rb_raise(rb_eStandardError, strerror(errno));
49 hdr = (struct nlmsghdr *)buff;
51 if (NLMSG_ERROR == hdr->nlmsg_type) {
52 rb_raise(rb_eStandardError, strerror(errno));
53 } else if (NLMSG_DONE == hdr->nlmsg_type) {
55 event = (struct proc_event *)((struct cn_msg *)NLMSG_DATA(hdr))->data;
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);
63 rb_funcall(cEventHandler, m_call, 2, INT2FIX(event->event_data.exit.process_pid), ID2SYM(proc_exit));
64 return INT2FIX(1);
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);
72 rb_funcall(cEventHandler, m_call, 2, INT2FIX(event->event_data.fork.parent_pid), ID2SYM(proc_fork));
73 return INT2FIX(1);
77 return Qnil;
81 #define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \
82 sizeof(int))
84 void
85 connect_to_netlink()
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
92 /* connect to netlink socket */
93 nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
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();
100 bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
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();
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;
119 if (-1 == send(nl_sock, hdr, hdr->nlmsg_len, 0)) {
120 rb_raise(rb_eStandardError, strerror(errno));
124 void
125 Init_netlink_handler_ext()
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?");
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);
137 connect_to_netlink();
140 #endif