pipe.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. # Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
  2. #
  3. # This file is part of paramiko.
  4. #
  5. # Paramiko is free software; you can redistribute it and/or modify it under the
  6. # terms of the GNU Lesser General Public License as published by the Free
  7. # Software Foundation; either version 2.1 of the License, or (at your option)
  8. # any later version.
  9. #
  10. # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
  11. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  13. # details.
  14. #
  15. # You should have received a copy of the GNU Lesser General Public License
  16. # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
  17. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. """
  19. Abstraction of a one-way pipe where the read end can be used in
  20. `select.select`. Normally this is trivial, but Windows makes it nearly
  21. impossible.
  22. The pipe acts like an Event, which can be set or cleared. When set, the pipe
  23. will trigger as readable in `select <select.select>`.
  24. """
  25. import sys
  26. import os
  27. import socket
  28. def make_pipe():
  29. if sys.platform[:3] != "win":
  30. p = PosixPipe()
  31. else:
  32. p = WindowsPipe()
  33. return p
  34. class PosixPipe(object):
  35. def __init__(self):
  36. self._rfd, self._wfd = os.pipe()
  37. self._set = False
  38. self._forever = False
  39. self._closed = False
  40. def close(self):
  41. os.close(self._rfd)
  42. os.close(self._wfd)
  43. # used for unit tests:
  44. self._closed = True
  45. def fileno(self):
  46. return self._rfd
  47. def clear(self):
  48. if not self._set or self._forever:
  49. return
  50. os.read(self._rfd, 1)
  51. self._set = False
  52. def set(self):
  53. if self._set or self._closed:
  54. return
  55. self._set = True
  56. os.write(self._wfd, b"*")
  57. def set_forever(self):
  58. self._forever = True
  59. self.set()
  60. class WindowsPipe(object):
  61. """
  62. On Windows, only an OS-level "WinSock" may be used in select(), but reads
  63. and writes must be to the actual socket object.
  64. """
  65. def __init__(self):
  66. serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  67. serv.bind(("127.0.0.1", 0))
  68. serv.listen(1)
  69. # need to save sockets in _rsock/_wsock so they don't get closed
  70. self._rsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  71. self._rsock.connect(("127.0.0.1", serv.getsockname()[1]))
  72. self._wsock, addr = serv.accept()
  73. serv.close()
  74. self._set = False
  75. self._forever = False
  76. self._closed = False
  77. def close(self):
  78. self._rsock.close()
  79. self._wsock.close()
  80. # used for unit tests:
  81. self._closed = True
  82. def fileno(self):
  83. return self._rsock.fileno()
  84. def clear(self):
  85. if not self._set or self._forever:
  86. return
  87. self._rsock.recv(1)
  88. self._set = False
  89. def set(self):
  90. if self._set or self._closed:
  91. return
  92. self._set = True
  93. self._wsock.send(b"*")
  94. def set_forever(self):
  95. self._forever = True
  96. self.set()
  97. class OrPipe(object):
  98. def __init__(self, pipe):
  99. self._set = False
  100. self._partner = None
  101. self._pipe = pipe
  102. def set(self):
  103. self._set = True
  104. if not self._partner._set:
  105. self._pipe.set()
  106. def clear(self):
  107. self._set = False
  108. if not self._partner._set:
  109. self._pipe.clear()
  110. def make_or_pipe(pipe):
  111. """
  112. wraps a pipe into two pipe-like objects which are "or"d together to
  113. affect the real pipe. if either returned pipe is set, the wrapped pipe
  114. is set. when both are cleared, the wrapped pipe is cleared.
  115. """
  116. p1 = OrPipe(pipe)
  117. p2 = OrPipe(pipe)
  118. p1._partner = p2
  119. p2._partner = p1
  120. return p1, p2