PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/evergreen/lib/socket.py

https://github.com/kingxsp/evergreen
Python | 575 lines | 498 code | 40 blank | 37 comment | 66 complexity | f459e613e1e3d815d98bb9ba02d71abc MD5 | raw file
  1. #
  2. # This file is part of Evergreen. See the NOTICE for more information.
  3. #
  4. from __future__ import absolute_import
  5. import os
  6. import _socket
  7. import sys
  8. import warnings
  9. try:
  10. from time import monotonic as _time
  11. except ImportError:
  12. from time import time as _time
  13. import evergreen
  14. from evergreen import six
  15. from evergreen.event import Event
  16. from evergreen.patcher import slurp_properties
  17. from evergreen.timeout import Timeout
  18. is_windows = sys.platform == 'win32'
  19. if is_windows:
  20. from errno import WSAEINVAL as EINVAL
  21. from errno import WSAEWOULDBLOCK as EWOULDBLOCK
  22. from errno import WSAEINPROGRESS as EINPROGRESS
  23. from errno import WSAEALREADY as EALREADY
  24. from errno import WSAEISCONN as EISCONN
  25. EAGAIN = EWOULDBLOCK
  26. else:
  27. from errno import EINVAL
  28. from errno import EWOULDBLOCK
  29. from errno import EINPROGRESS
  30. from errno import EALREADY
  31. from errno import EISCONN
  32. from errno import EAGAIN
  33. from errno import EBADF
  34. import socket as __socket__
  35. __all__ = __socket__.__all__
  36. __patched__ = ['fromfd', 'socketpair', 'ssl', 'socket', 'SocketType',
  37. 'gethostbyname', 'gethostbyname_ex', 'getnameinfo', 'getaddrinfo',
  38. 'create_connection',]
  39. slurp_properties(__socket__, globals(), ignore=__patched__, srckeys=dir(__socket__))
  40. del slurp_properties
  41. if six.PY3:
  42. from socket import socket as __socket__socket__
  43. # for ssl.py to create weakref
  44. class _realsocket(_socket.socket):
  45. pass
  46. class _fileobject:
  47. def __init__(self, sock, mode='rwb', bufsize=-1, close=False):
  48. super().__init__()
  49. self._sock = sock
  50. self._close = close
  51. self._obj = __socket__socket__.makefile(sock, mode, bufsize)
  52. @property
  53. def closed(self):
  54. return self._obj.closed
  55. def __del__(self):
  56. try:
  57. self.close()
  58. except:
  59. pass
  60. def close(self):
  61. try:
  62. if self._obj is not None:
  63. self._obj.close()
  64. if self._sock is not None and self._close:
  65. self._sock.close()
  66. finally:
  67. self._sock = self._obj = None
  68. for _name in ['fileno', 'flush', 'isatty', 'readable', 'readline',
  69. 'readlines', 'seek', 'seekable', 'tell', 'truncate',
  70. 'writable', 'writelines', 'read', 'write', 'readinto',
  71. 'readall']:
  72. exec('''def %s(self, *args, **kwargs):
  73. return getattr(self._obj, '%s')(*args, **kwargs)
  74. ''' % (_name, _name))
  75. del _name
  76. else:
  77. _fileobject = __socket__._fileobject
  78. _realsocket = _socket.socket
  79. try:
  80. _GLOBAL_DEFAULT_TIMEOUT = __socket__._GLOBAL_DEFAULT_TIMEOUT
  81. except AttributeError:
  82. _GLOBAL_DEFAULT_TIMEOUT = object()
  83. def _get_memory(string, offset):
  84. try:
  85. return memoryview(string)[offset:]
  86. except TypeError:
  87. return buffer(string, offset)
  88. class _closedsocket(object):
  89. __slots__ = []
  90. def _dummy(*args, **kwargs):
  91. raise error(EBADF, 'Bad file descriptor')
  92. # All _delegate_methods must also be initialized here.
  93. send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy
  94. __getattr__ = _dummy
  95. cancel_wait_ex = error(EBADF, 'File descriptor was closed by another task')
  96. class IOHandler(object):
  97. def __init__(self, fd):
  98. self.fd = fd
  99. self._read_closed = False
  100. self._write_closed = False
  101. self._read_event = Event()
  102. self._write_event = Event()
  103. def wait_read(self, timeout=None, timeout_exc=None):
  104. if self._read_closed:
  105. raise cancel_wait_ex
  106. self._read_event.clear()
  107. loop = evergreen.current.loop
  108. handler = loop.add_reader(self.fd, self._read_event.set)
  109. try:
  110. self._wait(self._read_event, timeout, timeout_exc)
  111. if self._read_closed:
  112. raise cancel_wait_ex
  113. finally:
  114. handler.cancel()
  115. loop.remove_reader(self.fd)
  116. def wait_write(self, timeout=None, timeout_exc=None):
  117. if self._write_closed:
  118. raise cancel_wait_ex
  119. self._write_event.clear()
  120. loop = evergreen.current.loop
  121. handler = loop.add_writer(self.fd, self._write_event.set)
  122. try:
  123. self._wait(self._write_event, timeout, timeout_exc)
  124. if self._write_closed:
  125. raise cancel_wait_ex
  126. finally:
  127. handler.cancel()
  128. loop.remove_writer(self.fd)
  129. def close(self, read=True, write=True):
  130. if read:
  131. self._read_closed = True
  132. self._read_event.set()
  133. if write:
  134. self._write_closed = True
  135. self._write_event.set()
  136. def _wait(self, event, timeout, timeout_exc):
  137. r = event.wait(timeout)
  138. if not r and timeout_exc:
  139. raise timeout_exc
  140. def __repr__(self):
  141. return '<%s fd=%d>' % (self.__class__.__name__, self.fd)
  142. class socket(object):
  143. def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None):
  144. if _sock is None:
  145. self._sock = _realsocket(family, type, proto)
  146. self.timeout = _socket.getdefaulttimeout()
  147. else:
  148. if hasattr(_sock, '_sock'):
  149. self._sock = _sock._sock
  150. self.timeout = getattr(_sock, 'timeout', False)
  151. if self.timeout is False:
  152. self.timeout = _socket.getdefaulttimeout()
  153. else:
  154. self._sock = _sock
  155. self.timeout = _socket.getdefaulttimeout()
  156. self._io_refs = 0 # for Python 3
  157. self._sock.setblocking(0)
  158. self._io = IOHandler(self._sock.fileno())
  159. self._closed = False
  160. def _decref_socketios(self):
  161. if self._io_refs > 0:
  162. self._io_refs -= 1
  163. if self._closed:
  164. self.close()
  165. def __repr__(self):
  166. return '<%s at %s %s>' % (type(self).__name__, hex(id(self)), self._formatinfo())
  167. def __str__(self):
  168. return '<%s %s>' % (type(self).__name__, self._formatinfo())
  169. def _formatinfo(self):
  170. try:
  171. fileno = self.fileno()
  172. except Exception:
  173. fileno = str(sys.exc_info()[1])
  174. try:
  175. sockname = self.getsockname()
  176. sockname = '%s:%s' % sockname
  177. except Exception:
  178. sockname = None
  179. try:
  180. peername = self.getpeername()
  181. peername = '%s:%s' % peername
  182. except Exception:
  183. peername = None
  184. result = 'fileno=%s' % fileno
  185. if sockname is not None:
  186. result += ' sock=' + str(sockname)
  187. if peername is not None:
  188. result += ' peer=' + str(peername)
  189. if getattr(self, 'timeout', None) is not None:
  190. result += ' timeout=' + str(self.timeout)
  191. return result
  192. def accept(self):
  193. sock = self._sock
  194. while True:
  195. try:
  196. if six.PY3:
  197. fd, address = sock._accept()
  198. client_socket = _realsocket(self.family, self.type, self.proto, fileno=fd)
  199. else:
  200. client_socket, address = sock.accept()
  201. break
  202. except error:
  203. ex = sys.exc_info()[1]
  204. if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
  205. raise
  206. del ex
  207. six.exc_clear()
  208. self._io.wait_read(timeout=self.timeout, timeout_exc=timeout('timed out'))
  209. return socket(_sock=client_socket), address
  210. def close(self):
  211. # This function should not reference any globals. See Python issue #808164.
  212. self._closed = True
  213. if self._io_refs <= 0:
  214. self._real_close()
  215. def _real_close(self, _closedsocket=_closedsocket):
  216. self._io.close()
  217. try:
  218. if six.PY3:
  219. self._sock.close()
  220. finally:
  221. self._sock = _closedsocket()
  222. @property
  223. def closed(self):
  224. return isinstance(self._sock, _closedsocket)
  225. def connect(self, address):
  226. if self.timeout == 0.0:
  227. return self._sock.connect(address)
  228. sock = self._sock
  229. if isinstance(address, tuple):
  230. r = getaddrinfo(address[0], address[1], sock.family, sock.type, sock.proto)
  231. address = r[0][-1]
  232. timer = Timeout(self.timeout, timeout('timed out'))
  233. timer.start()
  234. try:
  235. while True:
  236. err = sock.getsockopt(SOL_SOCKET, SO_ERROR)
  237. if err:
  238. raise error(err, os.strerror(err))
  239. result = sock.connect_ex(address)
  240. if not result or result == EISCONN:
  241. break
  242. elif (result in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or (result == EINVAL and is_windows):
  243. self._io.wait_write()
  244. else:
  245. raise error(result, os.strerror(result))
  246. finally:
  247. timer.cancel()
  248. def connect_ex(self, address):
  249. try:
  250. return self.connect(address) or 0
  251. except timeout:
  252. return EAGAIN
  253. except error:
  254. ex = sys.exc_info()[1]
  255. if type(ex) is error:
  256. return ex.args[0]
  257. else:
  258. raise # gaierror is not silented by connect_ex
  259. def dup(self):
  260. """dup() -> socket object
  261. Return a new socket object connected to the same system resource.
  262. Note, that the new socket does not inherit the timeout."""
  263. return socket(_sock=self._sock)
  264. def makefile(self, mode='rwb', bufsize=-1):
  265. # Two things to look out for:
  266. # 1) Closing the original socket object should not close the
  267. # socket (hence creating a new instance)
  268. # 2) The resulting fileobject must keep the timeout in order
  269. # to be compatible with the stdlib's socket.makefile.
  270. if six.PY3:
  271. sock = self
  272. else:
  273. sock = type(self)(_sock=self)
  274. return _fileobject(sock, mode, bufsize)
  275. def recv(self, *args):
  276. sock = self._sock # keeping the reference so that fd is not closed during waiting
  277. while True:
  278. try:
  279. return sock.recv(*args)
  280. except error:
  281. ex = sys.exc_info()[1]
  282. if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
  283. raise
  284. del ex
  285. six.exc_clear()
  286. self._io.wait_read(timeout=self.timeout, timeout_exc=timeout('timed out'))
  287. def recvfrom(self, *args):
  288. sock = self._sock
  289. while True:
  290. try:
  291. return sock.recvfrom(*args)
  292. except error:
  293. ex = sys.exc_info()[1]
  294. if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
  295. raise
  296. del ex
  297. six.exc_clear()
  298. self._io.wait_read(timeout=self.timeout, timeout_exc=timeout('timed out'))
  299. def recvfrom_into(self, *args):
  300. sock = self._sock
  301. while True:
  302. try:
  303. return sock.recvfrom_into(*args)
  304. except error:
  305. ex = sys.exc_info()[1]
  306. if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
  307. raise
  308. del ex
  309. six.exc_clear()
  310. self._io.wait_read(timeout=self.timeout, timeout_exc=timeout('timed out'))
  311. def recv_into(self, *args):
  312. sock = self._sock
  313. while True:
  314. try:
  315. return sock.recv_into(*args)
  316. except error:
  317. ex = sys.exc_info()[1]
  318. if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
  319. raise
  320. del ex
  321. six.exc_clear()
  322. self._io.wait_read(timeout=self.timeout, timeout_exc=timeout('timed out'))
  323. def send(self, data, flags=0):
  324. sock = self._sock
  325. try:
  326. return sock.send(data, flags)
  327. except error:
  328. ex = sys.exc_info()[1]
  329. if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
  330. raise
  331. del ex
  332. six.exc_clear()
  333. self._io.wait_write(timeout=self.timeout, timeout_exc=timeout('timed out'))
  334. try:
  335. return sock.send(data, flags)
  336. except error:
  337. ex = sys.exc_info()[1]
  338. if ex.args[0] == EWOULDBLOCK:
  339. return 0
  340. raise
  341. def sendall(self, data, flags=0):
  342. if isinstance(data, six.text_type):
  343. data = data.encode()
  344. if self.timeout is None:
  345. data_sent = 0
  346. while data_sent < len(data):
  347. data_sent += self.send(_get_memory(data, data_sent), flags)
  348. else:
  349. timeleft = self.timeout
  350. end = _time() + timeleft
  351. data_sent = 0
  352. while True:
  353. data_sent += self.send(_get_memory(data, data_sent), flags, timeout=timeleft)
  354. if data_sent >= len(data):
  355. break
  356. timeleft = end - _time()
  357. if timeleft <= 0:
  358. raise timeout('timed out')
  359. def sendto(self, *args):
  360. sock = self._sock
  361. try:
  362. return sock.sendto(*args)
  363. except error:
  364. ex = sys.exc_info()[1]
  365. if ex.args[0] != EWOULDBLOCK or timeout == 0.0:
  366. raise
  367. del ex
  368. six.exc_clear()
  369. self._io.wait_write(timeout=self.timeout, timeout_exc=timeout('timed out'))
  370. try:
  371. return sock.sendto(*args)
  372. except error:
  373. ex = sys.exc_info()[1]
  374. if ex.args[0] == EWOULDBLOCK:
  375. return 0
  376. raise
  377. def setblocking(self, flag):
  378. if flag:
  379. self.timeout = None
  380. else:
  381. self.timeout = 0.0
  382. def settimeout(self, howlong):
  383. if howlong is not None:
  384. try:
  385. f = howlong.__float__
  386. except AttributeError:
  387. raise TypeError('a float is required')
  388. howlong = f()
  389. if howlong < 0.0:
  390. raise ValueError('Timeout value out of range')
  391. self.timeout = howlong
  392. def gettimeout(self):
  393. return self.timeout
  394. def shutdown(self, how):
  395. if how == 0: # SHUT_RD
  396. self._io.close(read=True, write=False)
  397. elif how == 1: # SHUT_WR
  398. self._io.close(read=False, write=True)
  399. else:
  400. self._io.close()
  401. self._sock.shutdown(how)
  402. family = property(lambda self: self._sock.family, doc="the socket family")
  403. type = property(lambda self: self._sock.type, doc="the socket type")
  404. proto = property(lambda self: self._sock.proto, doc="the socket protocol")
  405. # delegate the functions that we haven't implemented to the real socket object
  406. _s = ("def %s(self, *args): return self._sock.%s(*args)\n\n"
  407. "%s.__doc__ = _realsocket.%s.__doc__\n")
  408. for _m in set(('bind',
  409. 'connect',
  410. 'connect_ex',
  411. 'fileno',
  412. 'listen',
  413. 'getpeername',
  414. 'getsockname',
  415. 'getsockopt',
  416. 'setsockopt',
  417. 'sendall',
  418. 'setblocking',
  419. 'settimeout',
  420. 'gettimeout',
  421. 'shutdown')) - set(locals()):
  422. exec (_s % (_m, _m, _m, _m))
  423. del _m, _s
  424. SocketType = socket
  425. def gethostbyname(*args, **kw):
  426. loop = evergreen.current.loop
  427. return loop._threadpool.spawn(__socket__.gethostbyname, *args, **kw).wait()
  428. def gethostbyname_ex(*args, **kw):
  429. loop = evergreen.current.loop
  430. return loop._threadpool.spawn(__socket__.gethostbyname_ex, *args, **kw).wait()
  431. def getnameinfo(*args, **kw):
  432. loop = evergreen.current.loop
  433. return loop._threadpool.spawn(__socket__.getnameinfo, *args, **kw).wait()
  434. def getaddrinfo(*args, **kw):
  435. loop = evergreen.current.loop
  436. return loop._threadpool.spawn(__socket__.getaddrinfo, *args, **kw).wait()
  437. def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
  438. """Connect to *address* and return the socket object.
  439. Convenience function. Connect to *address* (a 2-tuple ``(host,
  440. port)``) and return the socket object. Passing the optional
  441. *timeout* parameter will set the timeout on the socket instance
  442. before attempting to connect. If no *timeout* is supplied, the
  443. global default timeout setting returned by :func:`getdefaulttimeout`
  444. is used. If *source_address* is set it must be a tuple of (host, port)
  445. for the socket to bind as a source address before making the connection.
  446. An host of '' or port 0 tells the OS to use the default.
  447. """
  448. host, port = address
  449. err = None
  450. for res in getaddrinfo(host, port, 0 if has_ipv6 else AF_INET, SOCK_STREAM):
  451. af, socktype, proto, _canonname, sa = res
  452. sock = None
  453. try:
  454. sock = socket(af, socktype, proto)
  455. if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
  456. sock.settimeout(timeout)
  457. if source_address:
  458. sock.bind(source_address)
  459. sock.connect(sa)
  460. return sock
  461. except error:
  462. err = sys.exc_info()[1]
  463. six.exc_clear()
  464. if sock is not None:
  465. sock.close()
  466. if err is not None:
  467. raise err
  468. else:
  469. raise error("getaddrinfo returns an empty list")
  470. try:
  471. __original_fromfd__ = __socket__.fromfd
  472. def fromfd(*args):
  473. return socket(__original_fromfd__(*args))
  474. except AttributeError:
  475. pass
  476. try:
  477. __original_socketpair__ = __socket__.socketpair
  478. def socketpair(*args):
  479. one, two = __original_socketpair__(*args)
  480. return socket(one), socket(two)
  481. except AttributeError:
  482. pass
  483. try:
  484. from evergreen.lib import ssl as ssl_module
  485. sslerror = __socket__.sslerror
  486. __socket__.ssl
  487. def ssl(sock, certificate=None, private_key=None):
  488. warnings.warn("socket.ssl() is deprecated. Use ssl.wrap_socket() instead.", DeprecationWarning, stacklevel=2)
  489. return ssl_module.sslwrap_simple(sock, private_key, certificate)
  490. except Exception:
  491. # if the real socket module doesn't have the ssl method or sslerror
  492. # exception, we can't emulate them
  493. pass