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.
 
 
 

192 lines
5.3 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 socket
  15. import select
  16. import errno
  17. WSAEINVAL = getattr(errno, 'WSAEINVAL', 10022)
  18. class TimeoutSocket:
  19. """
  20. A socket imposter that supports timeout limits.
  21. """
  22. def __init__(self, timeout=20, sock=None):
  23. self.timeout = float(timeout)
  24. self.inbuf = ''
  25. if sock is None:
  26. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  27. self.sock = sock
  28. self.sock.setblocking(0)
  29. self._rbuf = ''
  30. self._wbuf = ''
  31. def __getattr__(self, name):
  32. # Delegate to real socket attributes.
  33. return getattr(self.sock, name)
  34. def connect(self, *addr):
  35. timeout = self.timeout
  36. sock = self.sock
  37. try:
  38. # Non-blocking mode
  39. sock.setblocking(0)
  40. apply(sock.connect, addr)
  41. sock.setblocking(timeout != 0)
  42. return 1
  43. except socket.error, why:
  44. if not timeout:
  45. raise
  46. sock.setblocking(1)
  47. if len(why.args) == 1:
  48. code = 0
  49. else:
  50. code, why = why
  51. if code not in \
  52. (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK):
  53. raise
  54. r, w, e = select.select([], [sock], [], timeout)
  55. if w:
  56. try:
  57. apply(sock.connect, addr)
  58. return 1
  59. except socket.error, why:
  60. if len(why.args) == 1:
  61. code = 0
  62. else:
  63. code, why = why
  64. if code in (errno.EISCONN, WSAEINVAL):
  65. return 1
  66. raise
  67. raise TimeoutError('socket connect() timeout.')
  68. def send(self, data, flags=0):
  69. total = len(data)
  70. next = 0
  71. while 1:
  72. r, w, e = select.select([], [self.sock], [], self.timeout)
  73. if w:
  74. buff = data[next:next + 8192]
  75. sent = self.sock.send(buff, flags)
  76. next = next + sent
  77. if next == total:
  78. return total
  79. continue
  80. raise TimeoutError('socket send() timeout.')
  81. def recv(self, amt, flags=0):
  82. if select.select([self.sock], [], [], self.timeout)[0]:
  83. return self.sock.recv(amt, flags)
  84. raise TimeoutError('socket recv() timeout.')
  85. buffsize = 4096
  86. handles = 1
  87. def makefile(self, mode="r", buffsize=-1):
  88. self.handles = self.handles + 1
  89. self.mode = mode
  90. return self
  91. def close(self):
  92. self.handles = self.handles - 1
  93. if self.handles == 0 and self.sock.fileno() >= 0:
  94. self.sock.close()
  95. def read(self, n=-1):
  96. if not isinstance(n, type(1)):
  97. n = -1
  98. if n >= 0:
  99. k = len(self._rbuf)
  100. if n <= k:
  101. data = self._rbuf[:n]
  102. self._rbuf = self._rbuf[n:]
  103. return data
  104. n = n - k
  105. L = [self._rbuf]
  106. self._rbuf = ""
  107. while n > 0:
  108. new = self.recv(max(n, self.buffsize))
  109. if not new:
  110. break
  111. k = len(new)
  112. if k > n:
  113. L.append(new[:n])
  114. self._rbuf = new[n:]
  115. break
  116. L.append(new)
  117. n = n - k
  118. return "".join(L)
  119. k = max(4096, self.buffsize)
  120. L = [self._rbuf]
  121. self._rbuf = ""
  122. while 1:
  123. new = self.recv(k)
  124. if not new:
  125. break
  126. L.append(new)
  127. k = min(k * 2, 1024 ** 2)
  128. return "".join(L)
  129. def readline(self, limit=-1):
  130. data = ""
  131. i = self._rbuf.find('\n')
  132. while i < 0 and not (0 < limit <= len(self._rbuf)):
  133. new = self.recv(self.buffsize)
  134. if not new:
  135. break
  136. i = new.find('\n')
  137. if i >= 0:
  138. i = i + len(self._rbuf)
  139. self._rbuf = self._rbuf + new
  140. if i < 0:
  141. i = len(self._rbuf)
  142. else:
  143. i = i + 1
  144. if 0 <= limit < len(self._rbuf):
  145. i = limit
  146. data, self._rbuf = self._rbuf[:i], self._rbuf[i:]
  147. return data
  148. def readlines(self, sizehint=0):
  149. total = 0
  150. list = []
  151. while 1:
  152. line = self.readline()
  153. if not line:
  154. break
  155. list.append(line)
  156. total += len(line)
  157. if sizehint and total >= sizehint:
  158. break
  159. return list
  160. def writelines(self, list):
  161. self.send(''.join(list))
  162. def write(self, data):
  163. self.send(data)
  164. def flush(self):
  165. pass
  166. class TimeoutError(Exception):
  167. pass