mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-12-26 20:52:45 +01:00
180 lines
5.2 KiB
Python
180 lines
5.2 KiB
Python
|
"""Based on code from timeout_socket.py, with some tweaks for compatibility.
|
||
|
These tweaks should really be rolled back into timeout_socket, but it's
|
||
|
not totally clear who is maintaining it at this point. In the meantime,
|
||
|
we'll use a different module name for our tweaked version to avoid any
|
||
|
confusion.
|
||
|
|
||
|
The original timeout_socket is by:
|
||
|
|
||
|
Scott Cotton <scott@chronis.pobox.com>
|
||
|
Lloyd Zusman <ljz@asfast.com>
|
||
|
Phil Mayes <pmayes@olivebr.com>
|
||
|
Piers Lauder <piers@cs.su.oz.au>
|
||
|
Radovan Garabik <garabik@melkor.dnp.fmph.uniba.sk>
|
||
|
"""
|
||
|
|
||
|
ident = "$Id$"
|
||
|
|
||
|
import string, socket, select, errno
|
||
|
|
||
|
WSAEINVAL = getattr(errno, 'WSAEINVAL', 10022)
|
||
|
|
||
|
|
||
|
class TimeoutSocket:
|
||
|
"""A socket imposter that supports timeout limits."""
|
||
|
|
||
|
def __init__(self, timeout=20, sock=None):
|
||
|
self.timeout = float(timeout)
|
||
|
self.inbuf = ''
|
||
|
if sock is None:
|
||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||
|
self.sock = sock
|
||
|
self.sock.setblocking(0)
|
||
|
self._rbuf = ''
|
||
|
self._wbuf = ''
|
||
|
|
||
|
def __getattr__(self, name):
|
||
|
# Delegate to real socket attributes.
|
||
|
return getattr(self.sock, name)
|
||
|
|
||
|
def connect(self, *addr):
|
||
|
timeout = self.timeout
|
||
|
sock = self.sock
|
||
|
try:
|
||
|
# Non-blocking mode
|
||
|
sock.setblocking(0)
|
||
|
apply(sock.connect, addr)
|
||
|
sock.setblocking(timeout != 0)
|
||
|
return 1
|
||
|
except socket.error,why:
|
||
|
if not timeout:
|
||
|
raise
|
||
|
sock.setblocking(1)
|
||
|
if len(why.args) == 1:
|
||
|
code = 0
|
||
|
else:
|
||
|
code, why = why
|
||
|
if code not in (
|
||
|
errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK
|
||
|
):
|
||
|
raise
|
||
|
r,w,e = select.select([],[sock],[],timeout)
|
||
|
if w:
|
||
|
try:
|
||
|
apply(sock.connect, addr)
|
||
|
return 1
|
||
|
except socket.error,why:
|
||
|
if len(why.args) == 1:
|
||
|
code = 0
|
||
|
else:
|
||
|
code, why = why
|
||
|
if code in (errno.EISCONN, WSAEINVAL):
|
||
|
return 1
|
||
|
raise
|
||
|
raise TimeoutError('socket connect() timeout.')
|
||
|
|
||
|
def send(self, data, flags=0):
|
||
|
total = len(data)
|
||
|
next = 0
|
||
|
while 1:
|
||
|
r, w, e = select.select([],[self.sock], [], self.timeout)
|
||
|
if w:
|
||
|
buff = data[next:next + 8192]
|
||
|
sent = self.sock.send(buff, flags)
|
||
|
next = next + sent
|
||
|
if next == total:
|
||
|
return total
|
||
|
continue
|
||
|
raise TimeoutError('socket send() timeout.')
|
||
|
|
||
|
def recv(self, amt, flags=0):
|
||
|
if select.select([self.sock], [], [], self.timeout)[0]:
|
||
|
return self.sock.recv(amt, flags)
|
||
|
raise TimeoutError('socket recv() timeout.')
|
||
|
|
||
|
buffsize = 4096
|
||
|
handles = 1
|
||
|
|
||
|
def makefile(self, mode="r", buffsize=-1):
|
||
|
self.handles = self.handles + 1
|
||
|
self.mode = mode
|
||
|
return self
|
||
|
|
||
|
def close(self):
|
||
|
self.handles = self.handles - 1
|
||
|
if self.handles == 0 and self.sock.fileno() >= 0:
|
||
|
self.sock.close()
|
||
|
|
||
|
def read(self, n=-1):
|
||
|
if not isinstance(n, type(1)):
|
||
|
n = -1
|
||
|
if n >= 0:
|
||
|
k = len(self._rbuf)
|
||
|
if n <= k:
|
||
|
data = self._rbuf[:n]
|
||
|
self._rbuf = self._rbuf[n:]
|
||
|
return data
|
||
|
n = n - k
|
||
|
L = [self._rbuf]
|
||
|
self._rbuf = ""
|
||
|
while n > 0:
|
||
|
new = self.recv(max(n, self.buffsize))
|
||
|
if not new: break
|
||
|
k = len(new)
|
||
|
if k > n:
|
||
|
L.append(new[:n])
|
||
|
self._rbuf = new[n:]
|
||
|
break
|
||
|
L.append(new)
|
||
|
n = n - k
|
||
|
return "".join(L)
|
||
|
k = max(4096, self.buffsize)
|
||
|
L = [self._rbuf]
|
||
|
self._rbuf = ""
|
||
|
while 1:
|
||
|
new = self.recv(k)
|
||
|
if not new: break
|
||
|
L.append(new)
|
||
|
k = min(k*2, 1024**2)
|
||
|
return "".join(L)
|
||
|
|
||
|
def readline(self, limit=-1):
|
||
|
data = ""
|
||
|
i = self._rbuf.find('\n')
|
||
|
while i < 0 and not (0 < limit <= len(self._rbuf)):
|
||
|
new = self.recv(self.buffsize)
|
||
|
if not new: break
|
||
|
i = new.find('\n')
|
||
|
if i >= 0: i = i + len(self._rbuf)
|
||
|
self._rbuf = self._rbuf + new
|
||
|
if i < 0: i = len(self._rbuf)
|
||
|
else: i = i+1
|
||
|
if 0 <= limit < len(self._rbuf): i = limit
|
||
|
data, self._rbuf = self._rbuf[:i], self._rbuf[i:]
|
||
|
return data
|
||
|
|
||
|
def readlines(self, sizehint = 0):
|
||
|
total = 0
|
||
|
list = []
|
||
|
while 1:
|
||
|
line = self.readline()
|
||
|
if not line: break
|
||
|
list.append(line)
|
||
|
total += len(line)
|
||
|
if sizehint and total >= sizehint:
|
||
|
break
|
||
|
return list
|
||
|
|
||
|
def writelines(self, list):
|
||
|
self.send(''.join(list))
|
||
|
|
||
|
def write(self, data):
|
||
|
self.send(data)
|
||
|
|
||
|
def flush(self):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class TimeoutError(Exception):
|
||
|
pass
|