source: trunk/debathena/debathena/metrics/debathena/metrics/connector.pyx @ 25000

Revision 25000, 8.5 KB checked in by geofft, 13 years ago (diff)
In metrics: * Require that netlink messages come from the kernel, not from userspace. Patch by Nelson Elhage.
Line 
1cdef extern from "errno.h":
2    int errno
3
4cdef extern from "stdlib.h":
5    ctypedef long size_t
6
7cdef extern from "sys/types.h":
8    ctypedef long pid_t
9
10cdef extern from "sys/socket.h":
11    ctypedef long socklen_t
12    struct sockaddr:
13        pass
14
15    int socket(int, int, int)
16    int bind(int, sockaddr *, socklen_t)
17    size_t send(int, void *, size_t, int)
18    size_t recvfrom(int, void *, size_t, int, sockaddr *, socklen_t *)
19
20    enum:
21        SOCK_DGRAM
22        PF_NETLINK
23        AF_NETLINK
24
25cdef extern from "linux/netlink.h":
26    enum:
27        NETLINK_CONNECTOR
28        NLMSG_DONE
29    struct sockaddr_nl:
30        unsigned long nl_family
31        unsigned long nl_pad
32        unsigned long nl_pid
33        unsigned long nl_groups
34    struct nlmsghdr:
35        long nlmsg_len
36        long nlmsg_type
37        long nlmsg_flags
38        long nlmsg_seq
39        long nlmsg_pid
40    long NLMSG_LENGTH(long)
41    void * NLMSG_DATA(void *)
42
43cdef extern from "linux/connector.h":
44    enum:
45        CN_IDX_PROC
46        CN_VAL_PROC
47    struct cb_id:
48        long idx
49        long val
50    struct cn_msg:
51        cb_id id
52        long seq
53        long ack
54        long len
55        long flags
56        char data[0]
57
58cdef extern from "linux/cn_proc.h":
59    enum proc_cn_mcast_op:
60        PROC_CN_MCAST_LISTEN
61        PROC_CN_MCAST_IGNORE
62
63    enum what:
64        C_PROC_EVENT_NONE "PROC_EVENT_NONE"
65        C_PROC_EVENT_FORK "PROC_EVENT_FORK"
66        C_PROC_EVENT_EXEC "PROC_EVENT_EXEC"
67        C_PROC_EVENT_UID "PROC_EVENT_UID"
68        C_PROC_EVENT_GID "PROC_EVENT_GID"
69        C_PROC_EVENT_EXIT "PROC_EVENT_EXIT"
70
71    struct ack_proc_event:
72        long err
73    struct fork_proc_event:
74        pid_t parent_pid
75        pid_t parent_tgid
76        pid_t child_pid
77        pid_t child_tgid
78    struct exec_proc_event:
79        pid_t process_pid
80        pid_t process_tgid
81    union id_proc_event_r:
82        long ruid
83        long rgid
84    union id_proc_event_e:
85        long euid
86        long egid
87    struct id_proc_event:
88        pid_t process_pid
89        pid_t process_tgid
90        id_proc_event_r r
91        id_proc_event_e e
92    struct exit_proc_event:
93        pid_t process_pid
94        pid_t process_tgid
95        long exit_code
96        long exit_signal
97
98    union event_data:
99        ack_proc_event ack
100        fork_proc_event fork
101        exec_proc_event exec_ "exec"
102        id_proc_event id_ "id"
103        exit_proc_event exit_ "exit"
104
105    struct proc_event:
106        what what
107        long cpu
108        long timestamp_ns
109        event_data event_data
110
111cdef extern from "string.h":
112    char * strerror(int)
113
114cdef extern from "unistd.h":
115    pid_t getpid()
116    int close(int)
117
118
119PROC_EVENT_NONE = C_PROC_EVENT_NONE
120PROC_EVENT_FORK = C_PROC_EVENT_FORK
121PROC_EVENT_EXEC = C_PROC_EVENT_EXEC
122PROC_EVENT_UID = C_PROC_EVENT_UID
123PROC_EVENT_GID = C_PROC_EVENT_GID
124PROC_EVENT_EXIT = C_PROC_EVENT_EXIT
125
126
127cdef class ProcEvent:
128    cdef public long what
129    cdef public long cpu
130    cdef public long timestamp_ns
131
132
133cdef class AckProcEvent(ProcEvent):
134    cdef public long err
135
136    def __repr__(self):
137        return "<AckProcEvent err=%d>" % self.err
138
139
140cdef class ForkProcEvent(ProcEvent):
141    cdef public long parent_pid
142    cdef public long parent_tgid
143    cdef public long child_pid
144    cdef public long child_tgid
145
146    def __repr__(self):
147        return "<ForkProcEvent ppid=%d ptgid=%d pid=%d tgid=%d>" % (
148            self.parent_pid,
149            self.parent_tgid,
150            self.child_pid,
151            self.child_tgid)
152
153
154cdef class ExecProcEvent(ProcEvent):
155    cdef public long process_pid
156    cdef public long process_tgid
157
158    def __repr__(self):
159        return "<ExecProcEvent pid=%d tgid=%d>" % (
160            self.process_pid,
161            self.process_tgid)
162
163
164cdef class UidProcEvent(ProcEvent):
165    cdef public long process_pid
166    cdef public long process_tgid
167    cdef public long ruid
168    cdef public long euid
169
170    def __repr__(self):
171        return "<UidProcEvent pid=%d tgid=%d ruid=%d euid=%d>" % (
172            self.process_pid,
173            self.process_tgid,
174            self.ruid,
175            self.euid)
176
177
178cdef class GidProcEvent(ProcEvent):
179    cdef public long process_pid
180    cdef public long process_tgid
181    cdef public long rgid
182    cdef public long egid
183
184    def __repr__(self):
185        return "<GidProcEvent pid=%d tgid=%d rgid=%d egid=%d>" % (
186            self.process_pid,
187            self.process_tgid,
188            self.rgid,
189            self.egid)
190
191
192cdef class ExitProcEvent(ProcEvent):
193    cdef public long process_pid
194    cdef public long process_tgid
195    cdef public long exit_code
196    cdef public long exit_signal
197
198    def __repr__(self):
199        return "<ExitProcEvent pid=%d tgid=%d code=%d signal=%d>" % (
200            self.process_pid,
201            self.process_tgid,
202            self.exit_code,
203            self.exit_signal)
204
205
206cdef class UnknownProcEvent(ProcEvent):
207    def __repr__(self):
208        return "<UnknownProcEvent what=%d>" % self.what
209
210
211cdef class Connector:
212    cdef int sock
213    cdef public object closed
214
215    def __cinit__(self):
216        self.closed = False
217
218        cdef int flags
219        cdef sockaddr_nl my_addr
220        cdef char buf[4096]
221        cdef nlmsghdr *nl_hdr
222        cdef cn_msg *cn_hdr
223        cdef proc_cn_mcast_op *mcop_msg
224
225        self.sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR)
226
227        my_addr.nl_family = AF_NETLINK
228        my_addr.nl_groups = CN_IDX_PROC
229        my_addr.nl_pid = getpid()
230
231        if bind(self.sock, <sockaddr *>&my_addr, sizeof(my_addr)) < 0:
232            raise IOError(errno, strerror(errno))
233
234        nl_hdr = <nlmsghdr *>buf
235        nl_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(cn_msg) + sizeof(proc_cn_mcast_op))
236        nl_hdr.nlmsg_type = NLMSG_DONE
237        nl_hdr.nlmsg_flags = 0
238        nl_hdr.nlmsg_seq = 0
239        nl_hdr.nlmsg_pid = getpid()
240
241        cn_hdr = <cn_msg *>NLMSG_DATA(nl_hdr)
242        cn_hdr.id.idx = CN_IDX_PROC
243        cn_hdr.id.val = CN_VAL_PROC
244        cn_hdr.seq = 0
245        cn_hdr.ack = 0
246        cn_hdr.len = sizeof(proc_cn_mcast_op)
247
248        mcop_msg = <proc_cn_mcast_op *>cn_hdr.data
249        mcop_msg[0] = PROC_CN_MCAST_LISTEN
250
251        if send(self.sock, nl_hdr, nl_hdr.nlmsg_len, 0) != nl_hdr.nlmsg_len:
252            raise IOError(errno, strerror(errno))
253
254    def __dealloc__(self):
255        if not self.closed:
256            close(self.sock)
257
258    def fileno(self):
259        return self.sock
260
261    def close(self):
262        if not self.closed:
263            close(self.sock)
264            self.closed = True
265
266    def recv_event(self):
267        cdef char buf[4096]
268        cdef sockaddr_nl from_addr
269        cdef socklen_t s
270        cdef proc_event *ev
271        cdef object ret
272
273        s = sizeof(from_addr)
274
275        while True:
276            if recvfrom(self.sock, buf, sizeof(buf), 0,
277                        <sockaddr *>&from_addr, &s) == -1:
278                raise IOError(errno, strerror(errno))
279
280            if from_addr.nl_pid != 0:
281                # Ignore messages that don't come from the kernel
282                continue
283
284        ev = <proc_event *>((<cn_msg *>NLMSG_DATA(buf)).data)
285
286        if ev.what == PROC_EVENT_FORK:
287            ret = ForkProcEvent()
288            ret.parent_pid = ev.event_data.fork.parent_pid
289            ret.parent_tgid = ev.event_data.fork.parent_tgid
290            ret.child_pid = ev.event_data.fork.child_pid
291            ret.child_tgid = ev.event_data.fork.child_tgid
292        elif ev.what == PROC_EVENT_EXEC:
293            ret = ExecProcEvent()
294            ret.process_pid = ev.event_data.exec_.process_pid
295            ret.process_tgid = ev.event_data.exec_.process_tgid
296        elif ev.what == PROC_EVENT_UID:
297            ret = UidProcEvent()
298            ret.process_pid = ev.event_data.id_.process_pid
299            ret.process_tgid = ev.event_data.id_.process_tgid
300            ret.ruid = ev.event_data.id_.r.ruid
301            ret.euid = ev.event_data.id_.e.euid
302        elif ev.what == PROC_EVENT_GID:
303            ret = GidProcEvent()
304            ret.process_pid = ev.event_data.id_.process_pid
305            ret.process_tgid = ev.event_data.id_.process_tgid
306            ret.rgid = ev.event_data.id_.r.rgid
307            ret.egid = ev.event_data.id_.e.egid
308        elif ev.what == PROC_EVENT_EXIT:
309            ret = ExitProcEvent()
310            ret.process_pid = ev.event_data.exit_.process_pid
311            ret.process_tgid = ev.event_data.exit_.process_tgid
312            ret.exit_code = ev.event_data.exit_.exit_code
313            ret.exit_signal = ev.event_data.exit_.exit_signal
314        else:
315            ret = UnknownProcEvent()
316
317        ret.what = ev.what
318        ret.cpu = ev.cpu
319        ret.timestamp_ns = ev.timestamp_ns
320
321        return ret
Note: See TracBrowser for help on using the repository browser.