|
- """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>
- """
- 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
|