You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

180 lines
5.2 KiB

  1. """Based on code from timeout_socket.py, with some tweaks for compatibility.
  2. These tweaks should really be rolled back into timeout_socket, but it's
  3. not totally clear who is maintaining it at this point. In the meantime,
  4. we'll use a different module name for our tweaked version to avoid any
  5. confusion.
  6. The original timeout_socket is by:
  7. Scott Cotton <scott@chronis.pobox.com>
  8. Lloyd Zusman <ljz@asfast.com>
  9. Phil Mayes <pmayes@olivebr.com>
  10. Piers Lauder <piers@cs.su.oz.au>
  11. Radovan Garabik <garabik@melkor.dnp.fmph.uniba.sk>
  12. """
  13. ident = "$Id$"
  14. import string, socket, select, errno
  15. WSAEINVAL = getattr(errno, 'WSAEINVAL', 10022)
  16. class TimeoutSocket:
  17. """A socket imposter that supports timeout limits."""
  18. def __init__(self, timeout=20, sock=None):
  19. self.timeout = float(timeout)
  20. self.inbuf = ''
  21. if sock is None:
  22. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  23. self.sock = sock
  24. self.sock.setblocking(0)
  25. self._rbuf = ''
  26. self._wbuf = ''
  27. def __getattr__(self, name):
  28. # Delegate to real socket attributes.
  29. return getattr(self.sock, name)
  30. def connect(self, *addr):
  31. timeout = self.timeout
  32. sock = self.sock
  33. try:
  34. # Non-blocking mode
  35. sock.setblocking(0)
  36. apply(sock.connect, addr)
  37. sock.setblocking(timeout != 0)
  38. return 1
  39. except socket.error,why:
  40. if not timeout:
  41. raise
  42. sock.setblocking(1)
  43. if len(why.args) == 1:
  44. code = 0
  45. else:
  46. code, why = why
  47. if code not in (
  48. errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK
  49. ):
  50. raise
  51. r,w,e = select.select([],[sock],[],timeout)
  52. if w:
  53. try:
  54. apply(sock.connect, addr)
  55. return 1
  56. except socket.error,why:
  57. if len(why.args) == 1:
  58. code = 0
  59. else:
  60. code, why = why
  61. if code in (errno.EISCONN, WSAEINVAL):
  62. return 1
  63. raise
  64. raise TimeoutError('socket connect() timeout.')
  65. def send(self, data, flags=0):
  66. total = len(data)
  67. next = 0
  68. while 1:
  69. r, w, e = select.select([],[self.sock], [], self.timeout)
  70. if w:
  71. buff = data[next:next + 8192]
  72. sent = self.sock.send(buff, flags)
  73. next = next + sent
  74. if next == total:
  75. return total
  76. continue
  77. raise TimeoutError('socket send() timeout.')
  78. def recv(self, amt, flags=0):
  79. if select.select([self.sock], [], [], self.timeout)[0]:
  80. return self.sock.recv(amt, flags)
  81. raise TimeoutError('socket recv() timeout.')
  82. buffsize = 4096
  83. handles = 1
  84. def makefile(self, mode="r", buffsize=-1):
  85. self.handles = self.handles + 1
  86. self.mode = mode
  87. return self
  88. def close(self):
  89. self.handles = self.handles - 1
  90. if self.handles == 0 and self.sock.fileno() >= 0:
  91. self.sock.close()
  92. def read(self, n=-1):
  93. if not isinstance(n, type(1)):
  94. n = -1
  95. if n >= 0:
  96. k = len(self._rbuf)
  97. if n <= k:
  98. data = self._rbuf[:n]
  99. self._rbuf = self._rbuf[n:]
  100. return data
  101. n = n - k
  102. L = [self._rbuf]
  103. self._rbuf = ""
  104. while n > 0:
  105. new = self.recv(max(n, self.buffsize))
  106. if not new: break
  107. k = len(new)
  108. if k > n:
  109. L.append(new[:n])
  110. self._rbuf = new[n:]
  111. break
  112. L.append(new)
  113. n = n - k
  114. return "".join(L)
  115. k = max(4096, self.buffsize)
  116. L = [self._rbuf]
  117. self._rbuf = ""
  118. while 1:
  119. new = self.recv(k)
  120. if not new: break
  121. L.append(new)
  122. k = min(k*2, 1024**2)
  123. return "".join(L)
  124. def readline(self, limit=-1):
  125. data = ""
  126. i = self._rbuf.find('\n')
  127. while i < 0 and not (0 < limit <= len(self._rbuf)):
  128. new = self.recv(self.buffsize)
  129. if not new: break
  130. i = new.find('\n')
  131. if i >= 0: i = i + len(self._rbuf)
  132. self._rbuf = self._rbuf + new
  133. if i < 0: i = len(self._rbuf)
  134. else: i = i+1
  135. if 0 <= limit < len(self._rbuf): i = limit
  136. data, self._rbuf = self._rbuf[:i], self._rbuf[i:]
  137. return data
  138. def readlines(self, sizehint = 0):
  139. total = 0
  140. list = []
  141. while 1:
  142. line = self.readline()
  143. if not line: break
  144. list.append(line)
  145. total += len(line)
  146. if sizehint and total >= sizehint:
  147. break
  148. return list
  149. def writelines(self, list):
  150. self.send(''.join(list))
  151. def write(self, data):
  152. self.send(data)
  153. def flush(self):
  154. pass
  155. class TimeoutError(Exception):
  156. pass