fix UNIT and ID2SYM bugs
[god.git] / ext / god / netlink_handler.c
blobc8b5b9a7334a13d40b676209f295cba21a47c167
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 VALUE extra_data;
33 fd_set fds;
35 FD_ZERO(&fds);
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)) {
44 return INT2FIX(0);
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;
60 switch(event->what) {
61 case PROC_EVENT_EXIT:
62 if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.exit.process_pid))) {
63 return INT2FIX(0);
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);
72 return INT2FIX(1);
74 case PROC_EVENT_FORK:
75 if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.fork.parent_pid))) {
76 return INT2FIX(0);
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);
85 return INT2FIX(1);
87 case PROC_EVENT_NONE:
88 case PROC_EVENT_EXEC:
89 case PROC_EVENT_UID:
90 case PROC_EVENT_GID:
91 break;
95 return Qnil;
99 #define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \
100 sizeof(int))
102 void
103 connect_to_netlink()
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);
113 if (-1 == nl_sock) {
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));
126 /* Fill header */
127 hdr = (struct nlmsghdr *)buff;
128 hdr->nlmsg_len = NL_MESSAGE_SIZE;
129 hdr->nlmsg_type = NLMSG_DONE;
130 hdr->nlmsg_flags = 0;
131 hdr->nlmsg_seq = 0;
132 hdr->nlmsg_pid = getpid();
134 /* Fill message */
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;
138 msg->seq = 0;
139 msg->ack = 0;
140 msg->flags = 0;
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));
149 void
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();
165 #endif