X-Git-Url: https://git.distorted.org.uk/~mdw/mLib-python/blobdiff_plain/20bce5e92b01cd928f26b61be78215117039c561..579d01693c86259110fe7a2c2a6f005f1bdbad5b:/select.pyx diff --git a/select.pyx b/select.pyx deleted file mode 100644 index 28fe05d..0000000 --- a/select.pyx +++ /dev/null @@ -1,634 +0,0 @@ -# -*-pyrex-*- -# -# $Id$ -# -# Selectery -# -# (c) 2005 Straylight/Edgeware -# - -#----- Licensing notice ----------------------------------------------------- -# -# This file is part of the Python interface to mLib. -# -# mLib/Python is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# mLib/Python is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with mLib/Python; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#----- External dependencies ------------------------------------------------ - -cdef extern from 'stddef.h': - ctypedef int size_t -cdef extern from 'string.h': - void memcpy(void *p, void *q, size_t n) -cdef extern from 'errno.h': - int errno - enum: - EINTR - EAGAIN -cdef extern from 'math.h': - double modf(double x, double *i) -cdef extern from 'string.h': - char *strerror(int err) -cdef extern from 'sys/time.h': - struct timeval: - int tv_sec - int tv_usec -cdef extern from 'sys/types.h': - pass -cdef extern from 'sys/socket.h': - struct sockaddr: - int sa_family - enum: - AF_INET - int getsockname(int fd, sockaddr *pa, size_t *psz) - int getpeername(int fd, sockaddr *pa, size_t *psz) -cdef extern from 'arpa/inet.h': - struct in_addr: - int s_addr - int inet_aton(char *rp, in_addr *ia) - char *inet_ntoa(in_addr ia) -cdef extern from 'netinet/in.h': - struct sockaddr_in: - int sin_family - in_addr sin_addr - int sin_port - int htons(int x) - int htonl(int x) - int ntohs(int x) - int ntohl(int x) -cdef extern from 'netdb.h': - struct hostent: - char *h_name - char **h_aliases - int h_addrtype - int h_length - char **h_addr_list - char *h_addr - int h_errno - -cdef extern from 'mLib/sel.h': - ctypedef struct sel_state: - pass - ctypedef struct sel_file: - int fd - ctypedef struct sel_timer: - pass - enum: - SEL_READ - SEL_WRITE - SEL_EXC - void sel_init(sel_state *s) - void sel_initfile(sel_state *s, sel_file *f, int fd, unsigned mode, - void (*func)(int fd, unsigned mode, void *arg), - void *arg) - void sel_force(sel_file *f) - void sel_addfile(sel_file *f) - void sel_rmfile(sel_file *f) - void sel_addtimer(sel_state *s, sel_timer *t, timeval *tv, - void (*func)(timeval *tv, void *arg), - void *arg) - void sel_rmtimer(sel_timer *t) - int sel_select(sel_state *s) except * - -cdef extern from 'mLib/conn.h': - ctypedef struct conn: - pass - int conn_fd(conn *c, sel_state *s, int fd, - void (*func)(int fd, void *arg), void *arg) - void conn_kill(conn *c) - -cdef extern from 'mLib/bres.h': - ctypedef struct bres_client: - pass - void bres_byname(bres_client *r, char *name, - void (*func)(hostent *h, void *arg), void *arg) - void bres_byaddr(bres_client *r, in_addr addr, - void (*func)(hostent *h, void *arg), void *arg) - void bres_abort(bres_client *r) - void bres_exec(char *null) - void bres_init(sel_state *s) - -cdef extern from 'mLib/sig.h': - ctypedef struct sig: - pass - void sig_add(sig *s, int n, void (*func)(int n, void *arg), void *arg) - void sig_remove(sig *s) - void sig_init(sel_state *s) - -cdef extern from 'mLib/lbuf.h': - cdef struct lbuf: - int f - int delim - size_t sz - enum: - LBUF_ENABLE - LBUF_CRLF - LBUF_STRICTCRLF - -cdef extern from 'mLib/selbuf.h': - ctypedef struct selbuf: - sel_file reader - lbuf b - void selbuf_enable(selbuf *b) - void selbuf_disable(selbuf *b) - void selbuf_setsize(selbuf *b, size_t sz) - void selbuf_init(selbuf *b, sel_state *s, int fd, - void (*func)(char *s, size_t len, void *arg), void *arg) - void selbuf_destroy(selbuf *b) - -cdef extern from 'mLib/pkbuf.h': - ctypedef struct pkbuf: - int f - int want - enum: - PKBUF_ENABLE - -cdef extern from 'mLib/selpk.h': - ctypedef struct selpk: - sel_file reader - pkbuf pk - void selpk_enable(selpk *b) - void selpk_disable(selpk *b) - void selpk_want(selpk *b, size_t sz) - void selpk_init(selpk *b, sel_state *s, int fd, - void (*func)(unsigned char *p, size_t n, - pkbuf *pk, size_t *keep, void *arg), - void *arg) - void selpk_destroy(selpk *b) - -cdef extern from 'mLib/ident.h': - ctypedef struct ident_request: - pass - enum: - IDENT_USERID - IDENT_ERROR - IDENT_BAD - struct ident_userid: - char *os - char *user - union ident_u: - ident_userid userid - char *error - ctypedef struct ident_reply: - int sport - int dport - int type - ident_u u - void ident(ident_request *rq, sel_state *s, - sockaddr_in *local, sockaddr_in *remote, - void (*func)(ident_reply *r, void *arg), - void *arg) - void ident_abort(ident_request *rq) - -cdef extern from 'Python.h': - object PyString_FromStringAndSize(char *p, int len) - int PyString_AsStringAndSize(obj, char **p, int *len) except -1 - int PyObject_AsReadBuffer(obj, void **buf, int *len) except -1 - int PyObject_TypeCheck(obj, ty) - -cdef extern from 'grim.h': - int PSIZEOF(void *x) - -import socket -import signal - -#----- Utility functions ---------------------------------------------------- - -cdef _oserror(): - raise OSError, (errno, strerror(errno)) - -cdef object _tobool(int i): - if i: - return True - else: - return False - -cdef int _getfd(object fdobj): - try: - return fdobj - except TypeError: - return fdobj.fileno() - -#----- The global select state ---------------------------------------------- - -cdef sel_state sel - -sel_init(&sel) -bres_init(&sel) -bres_exec(NULL) -sig_init(&sel) - -def select(): - if sel_select(&sel) and errno != EINTR and errno != EAGAIN: - _oserror() - -#----- File selectors ------------------------------------------------------- - -READ = SEL_READ -WRITE = SEL_WRITE -EXCEPT = SEL_EXC - -cdef class File: - cdef sel_file f - cdef int _activep - cdef readonly unsigned mode - def __new__(me, fd, int mode = SEL_READ): - if (mode != SEL_READ and - mode != SEL_WRITE and - mode != SEL_EXC): - raise ValueError, 'bad select mode' - sel_initfile(&sel, &me.f, _getfd(fd), mode, _filefunc, me) - me._activep = 0 - me.mode = mode - def __dealloc__(me): - if me._activep: - sel_rmfile(&me.f) - property fd: - def __get__(me): - return me.f.fd - property activep: - def __get__(me): - return _tobool(me._activep) - def enable(me): - if me._activep: - raise ValueError, 'already enabled' - sel_addfile(&me.f) - me._activep = 1 - return me - def disable(me): - if not me._activep: - raise ValueError, 'already disabled' - sel_rmfile(&me.f) - me._activep = 0 - return me - def force(me): - sel_force(&me.f) - return me - def ready(me): - pass - -cdef void _filefunc(int fd, unsigned mode, void *arg): - cdef File sf - sf = arg - sf.ready() - -#----- Timer selectors ------------------------------------------------------ - -cdef double _tvtofloat(timeval *tv): - return tv.tv_sec + (tv.tv_usec / 1000000) -cdef void _floattotv(timeval *tv, double t): - cdef double s, us - us = modf(t, &s) - tv.tv_sec = s - tv.tv_usec = us * 1000000 - -cdef class Timer: - cdef sel_timer t - cdef int _activep - cdef readonly double time - def __new__(me, double when): - cdef timeval tv - _floattotv(&tv, when) - sel_addtimer(&sel, &me.t, &tv, _timerfunc, me) - me._activep = 1 - me.time = when - def __dealloc__(me): - if me._activep: - sel_rmtimer(&me.t) - property activep: - def __get__(me): - return _tobool(me._activep) - def kill(me): - if not me._activep: - raise ValueError, 'already dead' - sel_rmtimer(&me.t) - me._activep = 0 - return me - def timer(me, now): - pass - -cdef void _timerfunc(timeval *now, void *arg): - cdef Timer st - st = arg - st._activep = 0 - st.timer(_tvtofloat(now)) - -#----- Connections ---------------------------------------------------------- - -cdef class Connect: - cdef conn c - cdef int _activep - cdef readonly object socket - def __new__(me, sk): - conn_fd(&me.c, &sel, sk.fileno(), _connfunc, me) - me._activep = 1 - me.socket = sk - def __dealloc__(me): - if me._activep: - conn_kill(&me.c) - property activep: - def __get__(me): - return _tobool(me._activep) - def kill(me): - if not me._activep: - raise ValueError, 'already dead' - conn_kill(&me.c); - me._activep = 0 - return me - def connected(me): - pass - def error(me, errno, strerror): - pass - -cdef void _connfunc(int fd, void *arg): - cdef Connect c - c = arg - c._activep = 0 - if fd == -1: - c.socket = None - c.error(errno, strerror(errno)) - else: - c.connected() - -#----- Background name resolution ------------------------------------------- - -cdef class Resolve: - cdef bres_client r - cdef int _activep - def __init__(me, *hunoz, **hukairz): - raise TypeError, 'abstract class' - property activep: - def __get__(me): - return _tobool(me._activep) - def kill(me): - if not me._activep: - raise ValueError, 'already dead' - bres_abort(&me.r) - return me - def resolved(me, h): - pass - def failed(me): - pass - -cdef class ResolveByName (Resolve): - def __new__(me, char *name): - bres_byname(&me.r, name, _resfunc, me) - me._activep = 1 - def __init__(me, name): - pass - -cdef class ResolveByAddr (Resolve): - def __new__(me, char *addr): - cdef in_addr ia - if not inet_aton(addr, &ia): - raise TypeError, 'bad IP address' - bres_byaddr(&me.r, ia, _resfunc, me) - me._activep = 1 - def __init__(me, addr): - pass - -cdef void _resfunc(hostent *h, void *arg): - cdef Resolve r - cdef int i - r = arg - r._activep = 0 - if h is NULL: - r.failed(r) - else: - alias = [] - addr = [] - i = 0 - while h.h_aliases[i]: - alias.append(h.h_aliases[i]) - i = i + 1 - i = 0 - while h.h_addr_list[i]: - addr.append(inet_ntoa((h.h_addr_list[i])[0])) - i = i + 1 - r.resolved(h.h_name, alias, addr) - -#----- Signal handling ------------------------------------------------------ - -cdef class Signal: - cdef sig s - cdef int _activep - cdef readonly int signal - def __new__(me, int sig): - if sig < 0 or sig >= signal.NSIG: - raise ValueError, 'signal number out of range' - me.signal = sig - me._activep = 0 - def __dealloc__(me): - if me._activep: - sig_remove(&me.s) - def enable(me): - if me._activep: - raise ValueError, 'already enabled' - sig_add(&me.s, me.signal, _sigfunc, me) - me._activep = 1 - return me - def disable(me): - if not me._activep: - raise ValueError, 'already disabled' - sig_remove(&me.s) - me._activep = 0 - return me - def signalled(me): - pass - -cdef void _sigfunc(int sig, void *arg): - cdef Signal s - s = arg - s.signalled() - -#----- Line buffers --------------------------------------------------------- - -CRLF = LBUF_CRLF -STRICTCRLF = LBUF_STRICTCRLF - -cdef class LineBuffer: - cdef selbuf b - def __new__(me, fd): - selbuf_init(&me.b, &sel, _getfd(fd), _lbfunc, me) - selbuf_disable(&me.b) - def __dealloc__(me): - selbuf_destroy(&me.b) - property activep: - def __get__(me): - return _tobool(me.b.b.f & LFBUF_ENABLE) - property delim: - def __get__(me): - if me.b.b.delim == LBUF_CRLF or me.b.b.delim == LBUF_STRICTCRLF: - return me.b.b.delim - else: - return chr(me.b.b.delim) - def __set__(me, d): - if d == LBUF_CRLF or d == LBUF_STRICTCRLF: - me.b.b.delim = d - else: - me.b.b.delim = ord(d) - property size: - def __get__(me): - return me.b.b.sz - def __set__(me, sz): - selbuf_setsize(&me.b, sz) - def enable(me): - if me.b.b.f & LBUF_ENABLE: - raise ValueError, 'already enabled' - selbuf_enable(&me.b) - return me - def disable(me): - if not (me.b.b.f & LBUF_ENABLE): - raise ValueError, 'already disabled' - selbuf_disable(&me.b) - return me - def line(me, line): - pass - def eof(me): - pass - -cdef void _lbfunc(char *s, size_t n, void *arg): - cdef LineBuffer sb - sb = arg - if s is NULL: - sb.eof() - else: - sb.line(PyString_FromStringAndSize(s, n)) - -#----- Packet buffers ------------------------------------------------------- - -cdef class PacketBuffer: - cdef selpk p - def __new__(me, fd): - selpk_init(&me.p, &sel, _getfd(fd), _pkfunc, me) - selpk_disable(&me.p) - def __dealloc__(me): - selpk_destroy(&me.p) - property activep: - def __get__(me): - return _to_bool(me.p.pk.f & PKBUF_ENABLE) - property want: - def __get__(me): - return me.p.pk.want - def __set__(me, n): - selpk_want(&me.p, n) - def enable(me): - if me.p.pk.f & PKBUF_ENABLE: - raise ValueError, 'already enabled' - selpk_enable(&me.p) - return me - def disable(me): - if not (me.p.pk.f & PKBUF_ENABLE): - raise ValueError, 'already disabled' - selpk_disable(&me.p) - return me - def packet(me, pk): - return None - def eof(me): - pass - -cdef void _pkfunc(unsigned char *p, size_t n, pkbuf *pk, - size_t *keep, void *arg): - cdef PacketBuffer pb - cdef void *rp - cdef int rn - pb = arg - if p is NULL: - pb.eof() - else: - r = pb.packet(PyString_FromStringAndSize(p, n)) - if r is not None: - PyObject_AsReadBuffer(r, &rp, &rn) - if rn > n: - raise ValueError, 'remaining buffer too large' - if rn: - memcpy(p + n - rn, rp, rn) - keep[0] = rn - -#----- Ident client --------------------------------------------------------- - -cdef _inaddr_frompy(sockaddr_in *sin, addr): - cdef int port - if len(addr) != 2: - raise TypeError, 'want address/port pair' - a = addr[0] - if not inet_aton(a, &sin.sin_addr): - raise TypeError, 'bad IP address' - port = addr[1] - if not (0 <= port < 65536): - raise TypeError, 'port number out of range' - sin.sin_port = htons(port) - -cdef _inaddr_topy(sockaddr_in *sin): - return inet_ntoa(sin.sin_addr), ntohs(sin.sin_port) - -cdef class Identify: - cdef ident_request irq - cdef int _activep - cdef readonly localaddr - cdef readonly remoteaddr - def __new__(me, sk): - cdef sockaddr_in s_in, s_out - cdef size_t sz_in, sz_out - cdef int fd - if PyObject_TypeCheck(sk, socket.SocketType): - fd = sk.fileno() - sz_in = PSIZEOF(&s_in) - sz_out = PSIZEOF(&s_out) - if getsockname(fd, &s_in, &sz_in) or \ - getpeername(fd, &s_out, &sz_out): - _oserror() - if s_in.sin_family != AF_INET or s_out.sin_family != AF_INET: - raise TypeError, 'must be internet socket' - elif len(sk) != 2: - raise TypeError, 'want pair of addresses' - else: - _inaddr_frompy(&s_in, sk[0]) - _inaddr_frompy(&s_out, sk[1]) - ident(&me.irq, &sel, &s_in, &s_out, _identfunc, me) - me.localaddr = _inaddr_topy(&s_in) - me.remoteaddr = _inaddr_topy(&s_out) - me._activep = 1 - def __dealloc__(me): - if me._activep: - ident_abort(&me.irq) - property activep: - def __get__(me): - return _tobool(me._activep) - def kill(me): - if not me._activep: - raise ValueError, 'already disabled' - ident_abort(&me.irq) - me._activep = 0 - def user(me, os, user): - pass - def bad(me): - pass - def error(me, error): - pass - def failed(me, errno, strerror): - pass - -cdef void _identfunc(ident_reply *i, void *arg): - cdef Identify id - id = arg - id._activep = 0 - if i.type == IDENT_BAD: - ii.bad() - elif i.type == IDENT_ERROR: - ii.error(i.u.error) - elif i.type == IDENT_USER: - ii.user(i.u.userid.os, i.u.userid.user) - -#----- That's all, folks ----------------------------------------------------