7 # (c) 2005 Straylight/Edgeware
10 #----- Licensing notice -----------------------------------------------------
12 # This file is part of the Python interface to mLib.
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.
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.
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.
28 #----- External dependencies ------------------------------------------------
30 cdef extern from 'stddef.h':
32 cdef extern from 'string.h':
33 void memcpy(void *p, void *q, size_t n)
34 cdef extern from 'errno.h':
39 cdef extern from 'math.h':
40 double modf(double x, double *i)
41 cdef extern from 'string.h':
42 char *strerror(int err)
43 cdef extern from 'sys/time.h':
47 cdef extern from 'sys/types.h':
49 cdef extern from 'sys/socket.h':
54 int getsockname(int fd, sockaddr *pa, size_t *psz)
55 int getpeername(int fd, sockaddr *pa, size_t *psz)
56 cdef extern from 'arpa/inet.h':
59 int inet_aton(char *rp, in_addr *ia)
60 char *inet_ntoa(in_addr ia)
61 cdef extern from 'netinet/in.h':
70 cdef extern from 'netdb.h':
80 cdef extern from 'mLib/sel.h':
81 ctypedef struct sel_state:
83 ctypedef struct sel_file:
85 ctypedef struct sel_timer:
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),
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),
101 void sel_rmtimer(sel_timer *t)
102 int sel_select(sel_state *s) except *
104 cdef extern from 'mLib/conn.h':
105 ctypedef struct conn:
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)
111 cdef extern from 'mLib/bres.h':
112 ctypedef struct bres_client:
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)
122 cdef extern from 'mLib/sig.h':
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)
129 cdef extern from 'mLib/lbuf.h':
139 cdef extern from 'mLib/selbuf.h':
140 ctypedef struct selbuf:
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)
150 cdef extern from 'mLib/pkbuf.h':
151 ctypedef struct pkbuf:
157 cdef extern from 'mLib/selpk.h':
158 ctypedef struct selpk:
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),
168 void selpk_destroy(selpk *b)
170 cdef extern from 'mLib/ident.h':
171 ctypedef struct ident_request:
183 ctypedef struct ident_reply:
188 void ident(ident_request *rq, sel_state *s,
189 sockaddr_in *local, sockaddr_in *remote,
190 void (*func)(ident_reply *r, void *arg),
192 void ident_abort(ident_request *rq)
194 cdef 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)
200 cdef extern from 'grim.h':
206 #----- Utility functions ----------------------------------------------------
209 raise OSError, (errno, strerror(errno))
211 cdef object _tobool(int i):
217 cdef int _getfd(object fdobj):
221 return fdobj.fileno()
223 #----- The global select state ----------------------------------------------
233 if sel_select(&sel) and errno != EINTR and errno != EAGAIN:
236 #----- File selectors -------------------------------------------------------
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
250 raise ValueError, 'bad select mode'
251 sel_initfile(&sel, &me.f, _getfd(fd), mode, _filefunc, <void *>me)
262 return _tobool(me._activep)
265 raise ValueError, 'already enabled'
271 raise ValueError, 'already disabled'
281 cdef void _filefunc(int fd, unsigned mode, void *arg):
286 #----- Timer selectors ------------------------------------------------------
288 cdef double _tvtofloat(timeval *tv):
289 return tv.tv_sec + (tv.tv_usec / 1000000)
290 cdef void _floattotv(timeval *tv, double t):
294 tv.tv_usec = us * 1000000
299 cdef readonly double time
300 def __new__(me, double when):
302 _floattotv(&tv, when)
303 sel_addtimer(&sel, &me.t, &tv, _timerfunc, <void *>me)
311 return _tobool(me._activep)
314 raise ValueError, 'already dead'
321 cdef void _timerfunc(timeval *now, void *arg):
325 st.timer(_tvtofloat(now))
327 #----- Connections ----------------------------------------------------------
332 cdef readonly object socket
334 conn_fd(&me.c, &sel, sk.fileno(), _connfunc, <void *>me)
342 return _tobool(me._activep)
345 raise ValueError, 'already dead'
351 def error(me, errno, strerror):
354 cdef void _connfunc(int fd, void *arg):
360 c.error(errno, strerror(errno))
364 #----- Background name resolution -------------------------------------------
369 def __init__(me, *hunoz, **hukairz):
370 raise TypeError, 'abstract class'
373 return _tobool(me._activep)
376 raise ValueError, 'already dead'
384 cdef class ResolveByName (Resolve):
385 def __new__(me, char *name):
386 bres_byname(&me.r, name, _resfunc, <void *>me)
388 def __init__(me, name):
391 cdef class ResolveByAddr (Resolve):
392 def __new__(me, char *addr):
394 if not inet_aton(addr, &ia):
395 raise TypeError, 'bad IP address'
396 bres_byaddr(&me.r, ia, _resfunc, <void *>me)
398 def __init__(me, addr):
401 cdef void _resfunc(hostent *h, void *arg):
412 while h.h_aliases[i]:
413 alias.append(h.h_aliases[i])
416 while h.h_addr_list[i]:
417 addr.append(inet_ntoa((<in_addr *>h.h_addr_list[i])[0]))
419 r.resolved(h.h_name, alias, addr)
421 #----- Signal handling ------------------------------------------------------
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'
437 raise ValueError, 'already enabled'
438 sig_add(&me.s, me.signal, _sigfunc, <void *>me)
443 raise ValueError, 'already disabled'
450 cdef void _sigfunc(int sig, void *arg):
455 #----- Line buffers ---------------------------------------------------------
458 STRICTCRLF = LBUF_STRICTCRLF
460 cdef class LineBuffer:
463 selbuf_init(&me.b, &sel, _getfd(fd), _lbfunc, <void *>me)
464 selbuf_disable(&me.b)
466 selbuf_destroy(&me.b)
469 return _tobool(me.b.b.f & LFBUF_ENABLE)
472 if me.b.b.delim == LBUF_CRLF or me.b.b.delim == LBUF_STRICTCRLF:
475 return chr(me.b.b.delim)
477 if d == LBUF_CRLF or d == LBUF_STRICTCRLF:
480 me.b.b.delim = ord(d)
485 selbuf_setsize(&me.b, sz)
487 if me.b.b.f & LBUF_ENABLE:
488 raise ValueError, 'already enabled'
492 if not (me.b.b.f & LBUF_ENABLE):
493 raise ValueError, 'already disabled'
494 selbuf_disable(&me.b)
501 cdef void _lbfunc(char *s, size_t n, void *arg):
507 sb.line(PyString_FromStringAndSize(s, n))
509 #----- Packet buffers -------------------------------------------------------
511 cdef class PacketBuffer:
514 selpk_init(&me.p, &sel, _getfd(fd), _pkfunc, <void *>me)
520 return _to_bool(me.p.pk.f & PKBUF_ENABLE)
527 if me.p.pk.f & PKBUF_ENABLE:
528 raise ValueError, 'already enabled'
532 if not (me.p.pk.f & PKBUF_ENABLE):
533 raise ValueError, 'already disabled'
541 cdef void _pkfunc(unsigned char *p, size_t n, pkbuf *pk,
542 size_t *keep, void *arg):
546 pb = <PacketBuffer>arg
550 r = pb.packet(PyString_FromStringAndSize(<char *>p, n))
552 PyObject_AsReadBuffer(r, &rp, &rn)
554 raise ValueError, 'remaining buffer too large'
556 memcpy(p + n - rn, rp, rn)
559 #----- Ident client ---------------------------------------------------------
561 cdef _inaddr_frompy(sockaddr_in *sin, addr):
564 raise TypeError, 'want address/port pair'
566 if not inet_aton(a, &sin.sin_addr):
567 raise TypeError, 'bad IP address'
569 if not (0 <= port < 65536):
570 raise TypeError, 'port number out of range'
571 sin.sin_port = htons(port)
573 cdef _inaddr_topy(sockaddr_in *sin):
574 return inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)
577 cdef ident_request irq
579 cdef readonly localaddr
580 cdef readonly remoteaddr
582 cdef sockaddr_in s_in, s_out
583 cdef size_t sz_in, sz_out
585 if PyObject_TypeCheck(sk, socket.SocketType):
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):
592 if s_in.sin_family != AF_INET or s_out.sin_family != AF_INET:
593 raise TypeError, 'must be internet socket'
595 raise TypeError, 'want pair of addresses'
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)
608 return _tobool(me._activep)
611 raise ValueError, 'already disabled'
614 def user(me, os, user):
618 def error(me, error):
620 def failed(me, errno, strerror):
623 cdef void _identfunc(ident_reply *i, void *arg):
627 if i.type == IDENT_BAD:
629 elif i.type == IDENT_ERROR:
631 elif i.type == IDENT_USER:
632 ii.user(i.u.userid.os, i.u.userid.user)
634 #----- That's all, folks ----------------------------------------------------