Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

279 lignes
8.6 KiB

  1. cdef class UVBaseTransport(UVSocketHandle):
  2. def __cinit__(self):
  3. # Flow control
  4. self._high_water = FLOW_CONTROL_HIGH_WATER * 1024
  5. self._low_water = FLOW_CONTROL_HIGH_WATER // 4
  6. self._protocol = None
  7. self._protocol_connected = 0
  8. self._protocol_paused = 0
  9. self._protocol_data_received = None
  10. self._server = None
  11. self._waiter = None
  12. self._extra_info = None
  13. self._conn_lost = 0
  14. self._closing = 0
  15. cdef size_t _get_write_buffer_size(self):
  16. return 0
  17. cdef inline _schedule_call_connection_made(self):
  18. self._loop._call_soon_handle(
  19. new_MethodHandle(self._loop,
  20. "UVTransport._call_connection_made",
  21. <method_t>self._call_connection_made,
  22. self))
  23. cdef inline _schedule_call_connection_lost(self, exc):
  24. self._loop._call_soon_handle(
  25. new_MethodHandle1(self._loop,
  26. "UVTransport._call_connection_lost",
  27. <method1_t>self._call_connection_lost,
  28. self, exc))
  29. cdef _fatal_error(self, exc, throw, reason=None):
  30. # Overload UVHandle._fatal_error
  31. self._force_close(exc)
  32. if not isinstance(exc, OSError):
  33. if throw or self._loop is None:
  34. raise exc
  35. msg = f'Fatal error on transport {self.__class__.__name__}'
  36. if reason is not None:
  37. msg = f'{msg} ({reason})'
  38. self._loop.call_exception_handler({
  39. 'message': msg,
  40. 'exception': exc,
  41. 'transport': self,
  42. 'protocol': self._protocol,
  43. })
  44. cdef inline _maybe_pause_protocol(self):
  45. cdef:
  46. size_t size = self._get_write_buffer_size()
  47. if size <= self._high_water:
  48. return
  49. if not self._protocol_paused:
  50. self._protocol_paused = 1
  51. try:
  52. self._protocol.pause_writing()
  53. except Exception as exc:
  54. self._loop.call_exception_handler({
  55. 'message': 'protocol.pause_writing() failed',
  56. 'exception': exc,
  57. 'transport': self,
  58. 'protocol': self._protocol,
  59. })
  60. cdef inline _maybe_resume_protocol(self):
  61. cdef:
  62. size_t size = self._get_write_buffer_size()
  63. if self._protocol_paused and size <= self._low_water:
  64. self._protocol_paused = 0
  65. try:
  66. self._protocol.resume_writing()
  67. except Exception as exc:
  68. self._loop.call_exception_handler({
  69. 'message': 'protocol.resume_writing() failed',
  70. 'exception': exc,
  71. 'transport': self,
  72. 'protocol': self._protocol,
  73. })
  74. cdef _wakeup_waiter(self):
  75. if self._waiter is not None:
  76. if not self._waiter.cancelled():
  77. if not self._is_alive():
  78. self._waiter.set_exception(
  79. RuntimeError(
  80. 'closed Transport handle and unset waiter'))
  81. else:
  82. self._waiter.set_result(True)
  83. self._waiter = None
  84. cdef _call_connection_made(self):
  85. if self._protocol is None:
  86. raise RuntimeError(
  87. 'protocol is not set, cannot call connection_made()')
  88. # We use `_is_alive()` and not `_closing`, because we call
  89. # `transport._close()` in `loop.create_connection()` if an
  90. # exception happens during `await waiter`.
  91. if not self._is_alive():
  92. # A connection waiter can be cancelled between
  93. # 'await loop.create_connection()' and
  94. # `_schedule_call_connection_made` and
  95. # the actual `_call_connection_made`.
  96. self._wakeup_waiter()
  97. return
  98. # Set _protocol_connected to 1 before calling "connection_made":
  99. # if transport is aborted or closed, "connection_lost" will
  100. # still be scheduled.
  101. self._protocol_connected = 1
  102. try:
  103. self._protocol.connection_made(self)
  104. except BaseException:
  105. self._wakeup_waiter()
  106. raise
  107. if not self._is_alive():
  108. # This might happen when "transport.abort()" is called
  109. # from "Protocol.connection_made".
  110. self._wakeup_waiter()
  111. return
  112. self._start_reading()
  113. self._wakeup_waiter()
  114. cdef _call_connection_lost(self, exc):
  115. if self._waiter is not None:
  116. if not self._waiter.done():
  117. self._waiter.set_exception(exc)
  118. self._waiter = None
  119. if self._closed:
  120. # The handle is closed -- likely, _call_connection_lost
  121. # was already called before.
  122. return
  123. try:
  124. if self._protocol_connected:
  125. self._protocol.connection_lost(exc)
  126. finally:
  127. self._clear_protocol()
  128. self._close()
  129. server = self._server
  130. if server is not None:
  131. (<Server>server)._detach()
  132. self._server = None
  133. cdef inline _set_server(self, Server server):
  134. self._server = server
  135. (<Server>server)._attach()
  136. cdef inline _set_waiter(self, object waiter):
  137. if waiter is not None and not isfuture(waiter):
  138. raise TypeError(
  139. f'invalid waiter object {waiter!r}, expected asyncio.Future')
  140. self._waiter = waiter
  141. cdef _set_protocol(self, object protocol):
  142. self._protocol = protocol
  143. # Store a reference to the bound method directly
  144. try:
  145. self._protocol_data_received = protocol.data_received
  146. except AttributeError:
  147. pass
  148. cdef _clear_protocol(self):
  149. self._protocol = None
  150. self._protocol_data_received = None
  151. cdef inline _init_protocol(self):
  152. self._loop._track_transport(self)
  153. if self._protocol is None:
  154. raise RuntimeError('invalid _init_protocol call')
  155. self._schedule_call_connection_made()
  156. cdef inline _add_extra_info(self, str name, object obj):
  157. if self._extra_info is None:
  158. self._extra_info = {}
  159. self._extra_info[name] = obj
  160. cdef bint _is_reading(self):
  161. raise NotImplementedError
  162. cdef _start_reading(self):
  163. raise NotImplementedError
  164. cdef _stop_reading(self):
  165. raise NotImplementedError
  166. # === Public API ===
  167. property _paused:
  168. # Used by SSLProto. Might be removed in the future.
  169. def __get__(self):
  170. return bool(not self._is_reading())
  171. def get_protocol(self):
  172. return self._protocol
  173. def set_protocol(self, protocol):
  174. self._set_protocol(protocol)
  175. if self._is_reading():
  176. self._stop_reading()
  177. self._start_reading()
  178. def _force_close(self, exc):
  179. # Used by SSLProto. Might be removed in the future.
  180. if self._conn_lost or self._closed:
  181. return
  182. if not self._closing:
  183. self._closing = 1
  184. self._stop_reading()
  185. self._conn_lost += 1
  186. self._schedule_call_connection_lost(exc)
  187. def abort(self):
  188. self._force_close(None)
  189. def close(self):
  190. if self._closing or self._closed:
  191. return
  192. self._closing = 1
  193. self._stop_reading()
  194. if not self._get_write_buffer_size():
  195. # The write buffer is empty
  196. self._conn_lost += 1
  197. self._schedule_call_connection_lost(None)
  198. def is_closing(self):
  199. return self._closing
  200. def get_write_buffer_size(self):
  201. return self._get_write_buffer_size()
  202. def set_write_buffer_limits(self, high=None, low=None):
  203. self._ensure_alive()
  204. self._high_water, self._low_water = add_flowcontrol_defaults(
  205. high, low, FLOW_CONTROL_HIGH_WATER)
  206. self._maybe_pause_protocol()
  207. def get_write_buffer_limits(self):
  208. return (self._low_water, self._high_water)
  209. def get_extra_info(self, name, default=None):
  210. if self._extra_info is not None and name in self._extra_info:
  211. return self._extra_info[name]
  212. if name == 'socket':
  213. return self._get_socket()
  214. if name == 'sockname':
  215. return self._get_socket().getsockname()
  216. if name == 'peername':
  217. try:
  218. return self._get_socket().getpeername()
  219. except socket_error:
  220. return default
  221. return default