socketpair.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. # pylint: skip-file
  2. # vendored from https://github.com/mhils/backports.socketpair
  3. from __future__ import absolute_import
  4. import sys
  5. import socket
  6. import errno
  7. _LOCALHOST = '127.0.0.1'
  8. _LOCALHOST_V6 = '::1'
  9. if not hasattr(socket, "socketpair"):
  10. # Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain.
  11. def socketpair(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
  12. if family == socket.AF_INET:
  13. host = _LOCALHOST
  14. elif family == socket.AF_INET6:
  15. host = _LOCALHOST_V6
  16. else:
  17. raise ValueError("Only AF_INET and AF_INET6 socket address families "
  18. "are supported")
  19. if type != socket.SOCK_STREAM:
  20. raise ValueError("Only SOCK_STREAM socket type is supported")
  21. if proto != 0:
  22. raise ValueError("Only protocol zero is supported")
  23. # We create a connected TCP socket. Note the trick with
  24. # setblocking(False) that prevents us from having to create a thread.
  25. lsock = socket.socket(family, type, proto)
  26. try:
  27. lsock.bind((host, 0))
  28. lsock.listen(min(socket.SOMAXCONN, 128))
  29. # On IPv6, ignore flow_info and scope_id
  30. addr, port = lsock.getsockname()[:2]
  31. csock = socket.socket(family, type, proto)
  32. try:
  33. csock.setblocking(False)
  34. if sys.version_info >= (3, 0):
  35. try:
  36. csock.connect((addr, port))
  37. except (BlockingIOError, InterruptedError):
  38. pass
  39. else:
  40. try:
  41. csock.connect((addr, port))
  42. except socket.error as e:
  43. if e.errno != errno.WSAEWOULDBLOCK:
  44. raise
  45. csock.setblocking(True)
  46. ssock, _ = lsock.accept()
  47. except:
  48. csock.close()
  49. raise
  50. finally:
  51. lsock.close()
  52. return (ssock, csock)
  53. socket.socketpair = socketpair