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.
 
 
 

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