| 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 | |
| 30 | cdef extern from 'stddef.h': |
| 31 | ctypedef int size_t |
| 32 | cdef extern from 'string.h': |
| 33 | void memcpy(void *p, void *q, size_t n) |
| 34 | cdef extern from 'errno.h': |
| 35 | int errno |
| 36 | enum: |
| 37 | EINTR |
| 38 | EAGAIN |
| 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': |
| 44 | struct timeval: |
| 45 | int tv_sec |
| 46 | int tv_usec |
| 47 | cdef extern from 'sys/types.h': |
| 48 | pass |
| 49 | cdef 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) |
| 56 | cdef 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) |
| 61 | cdef 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) |
| 70 | cdef 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 | |
| 80 | cdef 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 | |
| 104 | cdef 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 | |
| 111 | cdef 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 | |
| 122 | cdef 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 | |
| 129 | cdef 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 | |
| 139 | cdef 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 | |
| 150 | cdef extern from 'mLib/pkbuf.h': |
| 151 | ctypedef struct pkbuf: |
| 152 | int f |
| 153 | int want |
| 154 | enum: |
| 155 | PKBUF_ENABLE |
| 156 | |
| 157 | cdef 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 | |
| 170 | cdef 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 | |
| 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) |
| 199 | |
| 200 | cdef extern from 'grim.h': |
| 201 | int PSIZEOF(void *x) |
| 202 | |
| 203 | import socket |
| 204 | import signal |
| 205 | |
| 206 | #----- Utility functions ---------------------------------------------------- |
| 207 | |
| 208 | cdef _oserror(): |
| 209 | raise OSError, (errno, strerror(errno)) |
| 210 | |
| 211 | cdef object _tobool(int i): |
| 212 | if i: |
| 213 | return True |
| 214 | else: |
| 215 | return False |
| 216 | |
| 217 | cdef int _getfd(object fdobj): |
| 218 | try: |
| 219 | return fdobj |
| 220 | except TypeError: |
| 221 | return fdobj.fileno() |
| 222 | |
| 223 | #----- The global select state ---------------------------------------------- |
| 224 | |
| 225 | cdef sel_state sel |
| 226 | |
| 227 | sel_init(&sel) |
| 228 | bres_init(&sel) |
| 229 | bres_exec(NULL) |
| 230 | sig_init(&sel) |
| 231 | |
| 232 | def select(): |
| 233 | if sel_select(&sel) and errno != EINTR and errno != EAGAIN: |
| 234 | _oserror() |
| 235 | |
| 236 | #----- File selectors ------------------------------------------------------- |
| 237 | |
| 238 | READ = SEL_READ |
| 239 | WRITE = SEL_WRITE |
| 240 | EXCEPT = SEL_EXC |
| 241 | |
| 242 | cdef 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 | |
| 281 | cdef void _filefunc(int fd, unsigned mode, void *arg): |
| 282 | cdef File sf |
| 283 | sf = <File>arg |
| 284 | sf.ready() |
| 285 | |
| 286 | #----- Timer selectors ------------------------------------------------------ |
| 287 | |
| 288 | cdef double _tvtofloat(timeval *tv): |
| 289 | return tv.tv_sec + (tv.tv_usec / 1000000) |
| 290 | cdef 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 | |
| 296 | cdef 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 | |
| 321 | cdef 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 | |
| 329 | cdef 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 | |
| 354 | cdef 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 | |
| 366 | cdef 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 | |
| 384 | cdef 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 | |
| 391 | cdef 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 | |
| 401 | cdef 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 | |
| 423 | cdef 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 | |
| 450 | cdef void _sigfunc(int sig, void *arg): |
| 451 | cdef Signal s |
| 452 | s = <Signal>arg |
| 453 | s.signalled() |
| 454 | |
| 455 | #----- Line buffers --------------------------------------------------------- |
| 456 | |
| 457 | CRLF = LBUF_CRLF |
| 458 | STRICTCRLF = LBUF_STRICTCRLF |
| 459 | |
| 460 | cdef 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 | |
| 501 | cdef 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 | |
| 511 | cdef 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 | |
| 541 | cdef 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 | |
| 561 | cdef _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 | |
| 573 | cdef _inaddr_topy(sockaddr_in *sin): |
| 574 | return inet_ntoa(sin.sin_addr), ntohs(sin.sin_port) |
| 575 | |
| 576 | cdef 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 | |
| 623 | cdef 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 ---------------------------------------------------- |