chiark / gitweb /
Initial import.
[mLib-python] / select.pyx
... / ...
CommitLineData
1# -*-pyrex-*-
2#
3# $Id$
4#
5# Selectery
6#
7# (c) 2005 Straylight/Edgeware
8#
9
10#----- Licensing notice -----------------------------------------------------
11#
12# This file is part of the Python interface to mLib.
13#
14# mLib/Python is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License as published by
16# the Free Software Foundation; either version 2 of the License, or
17# (at your option) any later version.
18#
19# mLib/Python is distributed in the hope that it will be useful,
20# but WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22# GNU General Public License for more details.
23#
24# You should have received a copy of the GNU General Public License
25# along with mLib/Python; if not, write to the Free Software Foundation,
26# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27
28#----- External dependencies ------------------------------------------------
29
30cdef extern from 'stddef.h':
31 ctypedef int size_t
32cdef extern from 'string.h':
33 void memcpy(void *p, void *q, size_t n)
34cdef extern from 'errno.h':
35 int errno
36 enum:
37 EINTR
38 EAGAIN
39cdef extern from 'math.h':
40 double modf(double x, double *i)
41cdef extern from 'string.h':
42 char *strerror(int err)
43cdef extern from 'sys/time.h':
44 struct timeval:
45 int tv_sec
46 int tv_usec
47cdef extern from 'sys/types.h':
48 pass
49cdef extern from 'sys/socket.h':
50 struct sockaddr:
51 int sa_family
52 enum:
53 AF_INET
54 int getsockname(int fd, sockaddr *pa, size_t *psz)
55 int getpeername(int fd, sockaddr *pa, size_t *psz)
56cdef extern from 'arpa/inet.h':
57 struct in_addr:
58 int s_addr
59 int inet_aton(char *rp, in_addr *ia)
60 char *inet_ntoa(in_addr ia)
61cdef extern from 'netinet/in.h':
62 struct sockaddr_in:
63 int sin_family
64 in_addr sin_addr
65 int sin_port
66 int htons(int x)
67 int htonl(int x)
68 int ntohs(int x)
69 int ntohl(int x)
70cdef extern from 'netdb.h':
71 struct hostent:
72 char *h_name
73 char **h_aliases
74 int h_addrtype
75 int h_length
76 char **h_addr_list
77 char *h_addr
78 int h_errno
79
80cdef extern from 'mLib/sel.h':
81 ctypedef struct sel_state:
82 pass
83 ctypedef struct sel_file:
84 int fd
85 ctypedef struct sel_timer:
86 pass
87 enum:
88 SEL_READ
89 SEL_WRITE
90 SEL_EXC
91 void sel_init(sel_state *s)
92 void sel_initfile(sel_state *s, sel_file *f, int fd, unsigned mode,
93 void (*func)(int fd, unsigned mode, void *arg),
94 void *arg)
95 void sel_force(sel_file *f)
96 void sel_addfile(sel_file *f)
97 void sel_rmfile(sel_file *f)
98 void sel_addtimer(sel_state *s, sel_timer *t, timeval *tv,
99 void (*func)(timeval *tv, void *arg),
100 void *arg)
101 void sel_rmtimer(sel_timer *t)
102 int sel_select(sel_state *s) except *
103
104cdef extern from 'mLib/conn.h':
105 ctypedef struct conn:
106 pass
107 int conn_fd(conn *c, sel_state *s, int fd,
108 void (*func)(int fd, void *arg), void *arg)
109 void conn_kill(conn *c)
110
111cdef extern from 'mLib/bres.h':
112 ctypedef struct bres_client:
113 pass
114 void bres_byname(bres_client *r, char *name,
115 void (*func)(hostent *h, void *arg), void *arg)
116 void bres_byaddr(bres_client *r, in_addr addr,
117 void (*func)(hostent *h, void *arg), void *arg)
118 void bres_abort(bres_client *r)
119 void bres_exec(char *null)
120 void bres_init(sel_state *s)
121
122cdef extern from 'mLib/sig.h':
123 ctypedef struct sig:
124 pass
125 void sig_add(sig *s, int n, void (*func)(int n, void *arg), void *arg)
126 void sig_remove(sig *s)
127 void sig_init(sel_state *s)
128
129cdef extern from 'mLib/lbuf.h':
130 cdef struct lbuf:
131 int f
132 int delim
133 size_t sz
134 enum:
135 LBUF_ENABLE
136 LBUF_CRLF
137 LBUF_STRICTCRLF
138
139cdef extern from 'mLib/selbuf.h':
140 ctypedef struct selbuf:
141 sel_file reader
142 lbuf b
143 void selbuf_enable(selbuf *b)
144 void selbuf_disable(selbuf *b)
145 void selbuf_setsize(selbuf *b, size_t sz)
146 void selbuf_init(selbuf *b, sel_state *s, int fd,
147 void (*func)(char *s, size_t len, void *arg), void *arg)
148 void selbuf_destroy(selbuf *b)
149
150cdef extern from 'mLib/pkbuf.h':
151 ctypedef struct pkbuf:
152 int f
153 int want
154 enum:
155 PKBUF_ENABLE
156
157cdef extern from 'mLib/selpk.h':
158 ctypedef struct selpk:
159 sel_file reader
160 pkbuf pk
161 void selpk_enable(selpk *b)
162 void selpk_disable(selpk *b)
163 void selpk_want(selpk *b, size_t sz)
164 void selpk_init(selpk *b, sel_state *s, int fd,
165 void (*func)(unsigned char *p, size_t n,
166 pkbuf *pk, size_t *keep, void *arg),
167 void *arg)
168 void selpk_destroy(selpk *b)
169
170cdef extern from 'mLib/ident.h':
171 ctypedef struct ident_request:
172 pass
173 enum:
174 IDENT_USERID
175 IDENT_ERROR
176 IDENT_BAD
177 struct ident_userid:
178 char *os
179 char *user
180 union ident_u:
181 ident_userid userid
182 char *error
183 ctypedef struct ident_reply:
184 int sport
185 int dport
186 int type
187 ident_u u
188 void ident(ident_request *rq, sel_state *s,
189 sockaddr_in *local, sockaddr_in *remote,
190 void (*func)(ident_reply *r, void *arg),
191 void *arg)
192 void ident_abort(ident_request *rq)
193
194cdef extern from 'Python.h':
195 object PyString_FromStringAndSize(char *p, int len)
196 int PyString_AsStringAndSize(obj, char **p, int *len) except -1
197 int PyObject_AsReadBuffer(obj, void **buf, int *len) except -1
198 int PyObject_TypeCheck(obj, ty)
199
200cdef extern from 'grim.h':
201 int PSIZEOF(void *x)
202
203import socket
204import signal
205
206#----- Utility functions ----------------------------------------------------
207
208cdef _oserror():
209 raise OSError, (errno, strerror(errno))
210
211cdef object _tobool(int i):
212 if i:
213 return True
214 else:
215 return False
216
217cdef int _getfd(object fdobj):
218 try:
219 return fdobj
220 except TypeError:
221 return fdobj.fileno()
222
223#----- The global select state ----------------------------------------------
224
225cdef sel_state sel
226
227sel_init(&sel)
228bres_init(&sel)
229bres_exec(NULL)
230sig_init(&sel)
231
232def select():
233 if sel_select(&sel) and errno != EINTR and errno != EAGAIN:
234 _oserror()
235
236#----- File selectors -------------------------------------------------------
237
238READ = SEL_READ
239WRITE = SEL_WRITE
240EXCEPT = SEL_EXC
241
242cdef class File:
243 cdef sel_file f
244 cdef int _activep
245 cdef readonly unsigned mode
246 def __new__(me, fd, int mode = SEL_READ):
247 if (mode != SEL_READ and
248 mode != SEL_WRITE and
249 mode != SEL_EXC):
250 raise ValueError, 'bad select mode'
251 sel_initfile(&sel, &me.f, _getfd(fd), mode, _filefunc, <void *>me)
252 me._activep = 0
253 me.mode = mode
254 def __dealloc__(me):
255 if me._activep:
256 sel_rmfile(&me.f)
257 property fd:
258 def __get__(me):
259 return me.f.fd
260 property activep:
261 def __get__(me):
262 return _tobool(me._activep)
263 def enable(me):
264 if me._activep:
265 raise ValueError, 'already enabled'
266 sel_addfile(&me.f)
267 me._activep = 1
268 return me
269 def disable(me):
270 if not me._activep:
271 raise ValueError, 'already disabled'
272 sel_rmfile(&me.f)
273 me._activep = 0
274 return me
275 def force(me):
276 sel_force(&me.f)
277 return me
278 def ready(me):
279 pass
280
281cdef void _filefunc(int fd, unsigned mode, void *arg):
282 cdef File sf
283 sf = <File>arg
284 sf.ready()
285
286#----- Timer selectors ------------------------------------------------------
287
288cdef double _tvtofloat(timeval *tv):
289 return tv.tv_sec + (tv.tv_usec / 1000000)
290cdef void _floattotv(timeval *tv, double t):
291 cdef double s, us
292 us = modf(t, &s)
293 tv.tv_sec = s
294 tv.tv_usec = us * 1000000
295
296cdef class Timer:
297 cdef sel_timer t
298 cdef int _activep
299 cdef readonly double time
300 def __new__(me, double when):
301 cdef timeval tv
302 _floattotv(&tv, when)
303 sel_addtimer(&sel, &me.t, &tv, _timerfunc, <void *>me)
304 me._activep = 1
305 me.time = when
306 def __dealloc__(me):
307 if me._activep:
308 sel_rmtimer(&me.t)
309 property activep:
310 def __get__(me):
311 return _tobool(me._activep)
312 def kill(me):
313 if not me._activep:
314 raise ValueError, 'already dead'
315 sel_rmtimer(&me.t)
316 me._activep = 0
317 return me
318 def timer(me, now):
319 pass
320
321cdef void _timerfunc(timeval *now, void *arg):
322 cdef Timer st
323 st = <Timer>arg
324 st._activep = 0
325 st.timer(_tvtofloat(now))
326
327#----- Connections ----------------------------------------------------------
328
329cdef class Connect:
330 cdef conn c
331 cdef int _activep
332 cdef readonly object socket
333 def __new__(me, sk):
334 conn_fd(&me.c, &sel, sk.fileno(), _connfunc, <void *>me)
335 me._activep = 1
336 me.socket = sk
337 def __dealloc__(me):
338 if me._activep:
339 conn_kill(&me.c)
340 property activep:
341 def __get__(me):
342 return _tobool(me._activep)
343 def kill(me):
344 if not me._activep:
345 raise ValueError, 'already dead'
346 conn_kill(&me.c);
347 me._activep = 0
348 return me
349 def connected(me):
350 pass
351 def error(me, errno, strerror):
352 pass
353
354cdef void _connfunc(int fd, void *arg):
355 cdef Connect c
356 c = <Connect>arg
357 c._activep = 0
358 if fd == -1:
359 c.socket = None
360 c.error(errno, strerror(errno))
361 else:
362 c.connected()
363
364#----- Background name resolution -------------------------------------------
365
366cdef class Resolve:
367 cdef bres_client r
368 cdef int _activep
369 def __init__(me, *hunoz, **hukairz):
370 raise TypeError, 'abstract class'
371 property activep:
372 def __get__(me):
373 return _tobool(me._activep)
374 def kill(me):
375 if not me._activep:
376 raise ValueError, 'already dead'
377 bres_abort(&me.r)
378 return me
379 def resolved(me, h):
380 pass
381 def failed(me):
382 pass
383
384cdef class ResolveByName (Resolve):
385 def __new__(me, char *name):
386 bres_byname(&me.r, name, _resfunc, <void *>me)
387 me._activep = 1
388 def __init__(me, name):
389 pass
390
391cdef class ResolveByAddr (Resolve):
392 def __new__(me, char *addr):
393 cdef in_addr ia
394 if not inet_aton(addr, &ia):
395 raise TypeError, 'bad IP address'
396 bres_byaddr(&me.r, ia, _resfunc, <void *>me)
397 me._activep = 1
398 def __init__(me, addr):
399 pass
400
401cdef void _resfunc(hostent *h, void *arg):
402 cdef Resolve r
403 cdef int i
404 r = <Resolve>arg
405 r._activep = 0
406 if h is NULL:
407 r.failed(r)
408 else:
409 alias = []
410 addr = []
411 i = 0
412 while h.h_aliases[i]:
413 alias.append(h.h_aliases[i])
414 i = i + 1
415 i = 0
416 while h.h_addr_list[i]:
417 addr.append(inet_ntoa((<in_addr *>h.h_addr_list[i])[0]))
418 i = i + 1
419 r.resolved(h.h_name, alias, addr)
420
421#----- Signal handling ------------------------------------------------------
422
423cdef class Signal:
424 cdef sig s
425 cdef int _activep
426 cdef readonly int signal
427 def __new__(me, int sig):
428 if sig < 0 or sig >= signal.NSIG:
429 raise ValueError, 'signal number out of range'
430 me.signal = sig
431 me._activep = 0
432 def __dealloc__(me):
433 if me._activep:
434 sig_remove(&me.s)
435 def enable(me):
436 if me._activep:
437 raise ValueError, 'already enabled'
438 sig_add(&me.s, me.signal, _sigfunc, <void *>me)
439 me._activep = 1
440 return me
441 def disable(me):
442 if not me._activep:
443 raise ValueError, 'already disabled'
444 sig_remove(&me.s)
445 me._activep = 0
446 return me
447 def signalled(me):
448 pass
449
450cdef void _sigfunc(int sig, void *arg):
451 cdef Signal s
452 s = <Signal>arg
453 s.signalled()
454
455#----- Line buffers ---------------------------------------------------------
456
457CRLF = LBUF_CRLF
458STRICTCRLF = LBUF_STRICTCRLF
459
460cdef class LineBuffer:
461 cdef selbuf b
462 def __new__(me, fd):
463 selbuf_init(&me.b, &sel, _getfd(fd), _lbfunc, <void *>me)
464 selbuf_disable(&me.b)
465 def __dealloc__(me):
466 selbuf_destroy(&me.b)
467 property activep:
468 def __get__(me):
469 return _tobool(me.b.b.f & LFBUF_ENABLE)
470 property delim:
471 def __get__(me):
472 if me.b.b.delim == LBUF_CRLF or me.b.b.delim == LBUF_STRICTCRLF:
473 return me.b.b.delim
474 else:
475 return chr(me.b.b.delim)
476 def __set__(me, d):
477 if d == LBUF_CRLF or d == LBUF_STRICTCRLF:
478 me.b.b.delim = d
479 else:
480 me.b.b.delim = ord(d)
481 property size:
482 def __get__(me):
483 return me.b.b.sz
484 def __set__(me, sz):
485 selbuf_setsize(&me.b, sz)
486 def enable(me):
487 if me.b.b.f & LBUF_ENABLE:
488 raise ValueError, 'already enabled'
489 selbuf_enable(&me.b)
490 return me
491 def disable(me):
492 if not (me.b.b.f & LBUF_ENABLE):
493 raise ValueError, 'already disabled'
494 selbuf_disable(&me.b)
495 return me
496 def line(me, line):
497 pass
498 def eof(me):
499 pass
500
501cdef void _lbfunc(char *s, size_t n, void *arg):
502 cdef LineBuffer sb
503 sb = <LineBuffer>arg
504 if s is NULL:
505 sb.eof()
506 else:
507 sb.line(PyString_FromStringAndSize(s, n))
508
509#----- Packet buffers -------------------------------------------------------
510
511cdef class PacketBuffer:
512 cdef selpk p
513 def __new__(me, fd):
514 selpk_init(&me.p, &sel, _getfd(fd), _pkfunc, <void *>me)
515 selpk_disable(&me.p)
516 def __dealloc__(me):
517 selpk_destroy(&me.p)
518 property activep:
519 def __get__(me):
520 return _to_bool(me.p.pk.f & PKBUF_ENABLE)
521 property want:
522 def __get__(me):
523 return me.p.pk.want
524 def __set__(me, n):
525 selpk_want(&me.p, n)
526 def enable(me):
527 if me.p.pk.f & PKBUF_ENABLE:
528 raise ValueError, 'already enabled'
529 selpk_enable(&me.p)
530 return me
531 def disable(me):
532 if not (me.p.pk.f & PKBUF_ENABLE):
533 raise ValueError, 'already disabled'
534 selpk_disable(&me.p)
535 return me
536 def packet(me, pk):
537 return None
538 def eof(me):
539 pass
540
541cdef void _pkfunc(unsigned char *p, size_t n, pkbuf *pk,
542 size_t *keep, void *arg):
543 cdef PacketBuffer pb
544 cdef void *rp
545 cdef int rn
546 pb = <PacketBuffer>arg
547 if p is NULL:
548 pb.eof()
549 else:
550 r = pb.packet(PyString_FromStringAndSize(<char *>p, n))
551 if r is not None:
552 PyObject_AsReadBuffer(r, &rp, &rn)
553 if rn > n:
554 raise ValueError, 'remaining buffer too large'
555 if rn:
556 memcpy(p + n - rn, rp, rn)
557 keep[0] = rn
558
559#----- Ident client ---------------------------------------------------------
560
561cdef _inaddr_frompy(sockaddr_in *sin, addr):
562 cdef int port
563 if len(addr) != 2:
564 raise TypeError, 'want address/port pair'
565 a = addr[0]
566 if not inet_aton(a, &sin.sin_addr):
567 raise TypeError, 'bad IP address'
568 port = addr[1]
569 if not (0 <= port < 65536):
570 raise TypeError, 'port number out of range'
571 sin.sin_port = htons(port)
572
573cdef _inaddr_topy(sockaddr_in *sin):
574 return inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)
575
576cdef class Identify:
577 cdef ident_request irq
578 cdef int _activep
579 cdef readonly localaddr
580 cdef readonly remoteaddr
581 def __new__(me, sk):
582 cdef sockaddr_in s_in, s_out
583 cdef size_t sz_in, sz_out
584 cdef int fd
585 if PyObject_TypeCheck(sk, socket.SocketType):
586 fd = sk.fileno()
587 sz_in = PSIZEOF(&s_in)
588 sz_out = PSIZEOF(&s_out)
589 if getsockname(fd, <sockaddr *>&s_in, &sz_in) or \
590 getpeername(fd, <sockaddr *>&s_out, &sz_out):
591 _oserror()
592 if s_in.sin_family != AF_INET or s_out.sin_family != AF_INET:
593 raise TypeError, 'must be internet socket'
594 elif len(sk) != 2:
595 raise TypeError, 'want pair of addresses'
596 else:
597 _inaddr_frompy(&s_in, sk[0])
598 _inaddr_frompy(&s_out, sk[1])
599 ident(&me.irq, &sel, &s_in, &s_out, _identfunc, <void *>me)
600 me.localaddr = _inaddr_topy(&s_in)
601 me.remoteaddr = _inaddr_topy(&s_out)
602 me._activep = 1
603 def __dealloc__(me):
604 if me._activep:
605 ident_abort(&me.irq)
606 property activep:
607 def __get__(me):
608 return _tobool(me._activep)
609 def kill(me):
610 if not me._activep:
611 raise ValueError, 'already disabled'
612 ident_abort(&me.irq)
613 me._activep = 0
614 def user(me, os, user):
615 pass
616 def bad(me):
617 pass
618 def error(me, error):
619 pass
620 def failed(me, errno, strerror):
621 pass
622
623cdef void _identfunc(ident_reply *i, void *arg):
624 cdef Identify id
625 id = <Identify>arg
626 id._activep = 0
627 if i.type == IDENT_BAD:
628 ii.bad()
629 elif i.type == IDENT_ERROR:
630 ii.error(i.u.error)
631 elif i.type == IDENT_USER:
632 ii.user(i.u.userid.os, i.u.userid.user)
633
634#----- That's all, folks ----------------------------------------------------