sslproto.pyx 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. cdef _create_transport_context(server_side, server_hostname):
  2. if server_side:
  3. raise ValueError('Server side SSL needs a valid SSLContext')
  4. # Client side may pass ssl=True to use a default
  5. # context; in that case the sslcontext passed is None.
  6. # The default is secure for client connections.
  7. # Python 3.4+: use up-to-date strong settings.
  8. sslcontext = ssl_create_default_context()
  9. if not server_hostname:
  10. sslcontext.check_hostname = False
  11. return sslcontext
  12. cdef class _SSLProtocolTransport:
  13. # TODO:
  14. # _sendfile_compatible = constants._SendfileMode.FALLBACK
  15. def __cinit__(self, Loop loop, ssl_protocol, context):
  16. self._loop = loop
  17. # SSLProtocol instance
  18. self._ssl_protocol = ssl_protocol
  19. self._closed = False
  20. if context is None:
  21. context = Context_CopyCurrent()
  22. self.context = context
  23. def get_extra_info(self, name, default=None):
  24. """Get optional transport information."""
  25. return self._ssl_protocol._get_extra_info(name, default)
  26. def set_protocol(self, protocol):
  27. self._ssl_protocol._set_app_protocol(protocol)
  28. def get_protocol(self):
  29. return self._ssl_protocol._app_protocol
  30. def is_closing(self):
  31. return self._closed
  32. def close(self):
  33. """Close the transport.
  34. Buffered data will be flushed asynchronously. No more data
  35. will be received. After all buffered data is flushed, the
  36. protocol's connection_lost() method will (eventually) called
  37. with None as its argument.
  38. """
  39. self._closed = True
  40. self._ssl_protocol._start_shutdown(self.context.copy())
  41. def __dealloc__(self):
  42. if not self._closed:
  43. self._closed = True
  44. warnings_warn(
  45. "unclosed transport <uvloop.loop._SSLProtocolTransport "
  46. "object>", ResourceWarning)
  47. def is_reading(self):
  48. return not self._ssl_protocol._app_reading_paused
  49. def pause_reading(self):
  50. """Pause the receiving end.
  51. No data will be passed to the protocol's data_received()
  52. method until resume_reading() is called.
  53. """
  54. self._ssl_protocol._pause_reading()
  55. def resume_reading(self):
  56. """Resume the receiving end.
  57. Data received will once again be passed to the protocol's
  58. data_received() method.
  59. """
  60. self._ssl_protocol._resume_reading(self.context.copy())
  61. def set_write_buffer_limits(self, high=None, low=None):
  62. """Set the high- and low-water limits for write flow control.
  63. These two values control when to call the protocol's
  64. pause_writing() and resume_writing() methods. If specified,
  65. the low-water limit must be less than or equal to the
  66. high-water limit. Neither value can be negative.
  67. The defaults are implementation-specific. If only the
  68. high-water limit is given, the low-water limit defaults to an
  69. implementation-specific value less than or equal to the
  70. high-water limit. Setting high to zero forces low to zero as
  71. well, and causes pause_writing() to be called whenever the
  72. buffer becomes non-empty. Setting low to zero causes
  73. resume_writing() to be called only once the buffer is empty.
  74. Use of zero for either limit is generally sub-optimal as it
  75. reduces opportunities for doing I/O and computation
  76. concurrently.
  77. """
  78. self._ssl_protocol._set_write_buffer_limits(high, low)
  79. self._ssl_protocol._control_app_writing(self.context.copy())
  80. def get_write_buffer_limits(self):
  81. return (self._ssl_protocol._outgoing_low_water,
  82. self._ssl_protocol._outgoing_high_water)
  83. def get_write_buffer_size(self):
  84. """Return the current size of the write buffers."""
  85. return self._ssl_protocol._get_write_buffer_size()
  86. def set_read_buffer_limits(self, high=None, low=None):
  87. """Set the high- and low-water limits for read flow control.
  88. These two values control when to call the upstream transport's
  89. pause_reading() and resume_reading() methods. If specified,
  90. the low-water limit must be less than or equal to the
  91. high-water limit. Neither value can be negative.
  92. The defaults are implementation-specific. If only the
  93. high-water limit is given, the low-water limit defaults to an
  94. implementation-specific value less than or equal to the
  95. high-water limit. Setting high to zero forces low to zero as
  96. well, and causes pause_reading() to be called whenever the
  97. buffer becomes non-empty. Setting low to zero causes
  98. resume_reading() to be called only once the buffer is empty.
  99. Use of zero for either limit is generally sub-optimal as it
  100. reduces opportunities for doing I/O and computation
  101. concurrently.
  102. """
  103. self._ssl_protocol._set_read_buffer_limits(high, low)
  104. self._ssl_protocol._control_ssl_reading()
  105. def get_read_buffer_limits(self):
  106. return (self._ssl_protocol._incoming_low_water,
  107. self._ssl_protocol._incoming_high_water)
  108. def get_read_buffer_size(self):
  109. """Return the current size of the read buffer."""
  110. return self._ssl_protocol._get_read_buffer_size()
  111. @property
  112. def _protocol_paused(self):
  113. # Required for sendfile fallback pause_writing/resume_writing logic
  114. return self._ssl_protocol._app_writing_paused
  115. def write(self, data):
  116. """Write some data bytes to the transport.
  117. This does not block; it buffers the data and arranges for it
  118. to be sent out asynchronously.
  119. """
  120. if not isinstance(data, (bytes, bytearray, memoryview)):
  121. raise TypeError(f"data: expecting a bytes-like instance, "
  122. f"got {type(data).__name__}")
  123. if not data:
  124. return
  125. self._ssl_protocol._write_appdata((data,), self.context.copy())
  126. def writelines(self, list_of_data):
  127. """Write a list (or any iterable) of data bytes to the transport.
  128. The default implementation concatenates the arguments and
  129. calls write() on the result.
  130. """
  131. self._ssl_protocol._write_appdata(list_of_data, self.context.copy())
  132. def write_eof(self):
  133. """Close the write end after flushing buffered data.
  134. This raises :exc:`NotImplementedError` right now.
  135. """
  136. raise NotImplementedError
  137. def can_write_eof(self):
  138. """Return True if this transport supports write_eof(), False if not."""
  139. return False
  140. def abort(self):
  141. """Close the transport immediately.
  142. Buffered data will be lost. No more data will be received.
  143. The protocol's connection_lost() method will (eventually) be
  144. called with None as its argument.
  145. """
  146. self._force_close(None)
  147. def _force_close(self, exc):
  148. self._closed = True
  149. self._ssl_protocol._abort(exc)
  150. def _test__append_write_backlog(self, data):
  151. # for test only
  152. self._ssl_protocol._write_backlog.append(data)
  153. self._ssl_protocol._write_buffer_size += len(data)
  154. cdef class SSLProtocol:
  155. """SSL protocol.
  156. Implementation of SSL on top of a socket using incoming and outgoing
  157. buffers which are ssl.MemoryBIO objects.
  158. """
  159. def __cinit__(self, *args, **kwargs):
  160. self._ssl_buffer_len = SSL_READ_MAX_SIZE
  161. self._ssl_buffer = <char*>PyMem_RawMalloc(self._ssl_buffer_len)
  162. if not self._ssl_buffer:
  163. raise MemoryError()
  164. def __dealloc__(self):
  165. PyMem_RawFree(self._ssl_buffer)
  166. self._ssl_buffer = NULL
  167. self._ssl_buffer_len = 0
  168. def __init__(self, loop, app_protocol, sslcontext, waiter,
  169. server_side=False, server_hostname=None,
  170. call_connection_made=True,
  171. ssl_handshake_timeout=None,
  172. ssl_shutdown_timeout=None):
  173. if ssl_handshake_timeout is None:
  174. ssl_handshake_timeout = SSL_HANDSHAKE_TIMEOUT
  175. elif ssl_handshake_timeout <= 0:
  176. raise ValueError(
  177. f"ssl_handshake_timeout should be a positive number, "
  178. f"got {ssl_handshake_timeout}")
  179. if ssl_shutdown_timeout is None:
  180. ssl_shutdown_timeout = SSL_SHUTDOWN_TIMEOUT
  181. elif ssl_shutdown_timeout <= 0:
  182. raise ValueError(
  183. f"ssl_shutdown_timeout should be a positive number, "
  184. f"got {ssl_shutdown_timeout}")
  185. if not sslcontext:
  186. sslcontext = _create_transport_context(
  187. server_side, server_hostname)
  188. self._server_side = server_side
  189. if server_hostname and not server_side:
  190. self._server_hostname = server_hostname
  191. else:
  192. self._server_hostname = None
  193. self._sslcontext = sslcontext
  194. # SSL-specific extra info. More info are set when the handshake
  195. # completes.
  196. self._extra = dict(sslcontext=sslcontext)
  197. # App data write buffering
  198. self._write_backlog = col_deque()
  199. self._write_buffer_size = 0
  200. self._waiter = waiter
  201. self._loop = loop
  202. self._set_app_protocol(app_protocol)
  203. self._app_transport = None
  204. self._app_transport_created = False
  205. # transport, ex: SelectorSocketTransport
  206. self._transport = None
  207. self._ssl_handshake_timeout = ssl_handshake_timeout
  208. self._ssl_shutdown_timeout = ssl_shutdown_timeout
  209. # SSL and state machine
  210. self._sslobj = None
  211. self._incoming = ssl_MemoryBIO()
  212. self._incoming_write = self._incoming.write
  213. self._outgoing = ssl_MemoryBIO()
  214. self._outgoing_read = self._outgoing.read
  215. self._state = UNWRAPPED
  216. self._conn_lost = 0 # Set when connection_lost called
  217. if call_connection_made:
  218. self._app_state = STATE_INIT
  219. else:
  220. self._app_state = STATE_CON_MADE
  221. # Flow Control
  222. self._ssl_writing_paused = False
  223. self._app_reading_paused = False
  224. self._ssl_reading_paused = False
  225. self._incoming_high_water = 0
  226. self._incoming_low_water = 0
  227. self._set_read_buffer_limits()
  228. self._app_writing_paused = False
  229. self._outgoing_high_water = 0
  230. self._outgoing_low_water = 0
  231. self._set_write_buffer_limits()
  232. cdef _set_app_protocol(self, app_protocol):
  233. self._app_protocol = app_protocol
  234. if (hasattr(app_protocol, 'get_buffer') and
  235. not isinstance(app_protocol, aio_Protocol)):
  236. self._app_protocol_get_buffer = app_protocol.get_buffer
  237. self._app_protocol_buffer_updated = app_protocol.buffer_updated
  238. self._app_protocol_is_buffer = True
  239. else:
  240. self._app_protocol_is_buffer = False
  241. cdef _wakeup_waiter(self, exc=None):
  242. if self._waiter is None:
  243. return
  244. if not self._waiter.cancelled():
  245. if exc is not None:
  246. self._waiter.set_exception(exc)
  247. else:
  248. self._waiter.set_result(None)
  249. self._waiter = None
  250. def _get_app_transport(self, context=None):
  251. if self._app_transport is None:
  252. if self._app_transport_created:
  253. raise RuntimeError('Creating _SSLProtocolTransport twice')
  254. self._app_transport = _SSLProtocolTransport(self._loop, self,
  255. context)
  256. self._app_transport_created = True
  257. return self._app_transport
  258. def connection_made(self, transport):
  259. """Called when the low-level connection is made.
  260. Start the SSL handshake.
  261. """
  262. self._transport = transport
  263. self._start_handshake()
  264. def connection_lost(self, exc):
  265. """Called when the low-level connection is lost or closed.
  266. The argument is an exception object or None (the latter
  267. meaning a regular EOF is received or the connection was
  268. aborted or closed).
  269. """
  270. self._write_backlog.clear()
  271. self._outgoing_read()
  272. self._conn_lost += 1
  273. # Just mark the app transport as closed so that its __dealloc__
  274. # doesn't complain.
  275. if self._app_transport is not None:
  276. self._app_transport._closed = True
  277. if self._state != DO_HANDSHAKE:
  278. if self._app_state == STATE_CON_MADE or \
  279. self._app_state == STATE_EOF:
  280. self._app_state = STATE_CON_LOST
  281. self._loop.call_soon(self._app_protocol.connection_lost, exc)
  282. self._set_state(UNWRAPPED)
  283. self._transport = None
  284. self._app_transport = None
  285. self._app_protocol = None
  286. self._wakeup_waiter(exc)
  287. if self._shutdown_timeout_handle:
  288. self._shutdown_timeout_handle.cancel()
  289. self._shutdown_timeout_handle = None
  290. if self._handshake_timeout_handle:
  291. self._handshake_timeout_handle.cancel()
  292. self._handshake_timeout_handle = None
  293. cdef get_buffer_impl(self, size_t n, char** buf, size_t* buf_size):
  294. cdef size_t want = n
  295. if want > SSL_READ_MAX_SIZE:
  296. want = SSL_READ_MAX_SIZE
  297. if self._ssl_buffer_len < want:
  298. self._ssl_buffer = <char*>PyMem_RawRealloc(self._ssl_buffer, want)
  299. if not self._ssl_buffer:
  300. raise MemoryError()
  301. self._ssl_buffer_len = want
  302. buf[0] = self._ssl_buffer
  303. buf_size[0] = self._ssl_buffer_len
  304. cdef buffer_updated_impl(self, size_t nbytes):
  305. self._incoming_write(PyMemoryView_FromMemory(
  306. self._ssl_buffer, nbytes, PyBUF_WRITE))
  307. if self._state == DO_HANDSHAKE:
  308. self._do_handshake()
  309. elif self._state == WRAPPED:
  310. self._do_read()
  311. elif self._state == FLUSHING:
  312. self._do_flush()
  313. elif self._state == SHUTDOWN:
  314. self._do_shutdown()
  315. def get_buffer(self, size_t n):
  316. # This pure python call is still used by some very peculiar test cases
  317. cdef:
  318. char* buf
  319. size_t buf_size
  320. self.get_buffer_impl(n, &buf, &buf_size)
  321. return PyMemoryView_FromMemory(buf, buf_size, PyBUF_WRITE)
  322. def buffer_updated(self, size_t nbytes):
  323. self.buffer_updated_impl(nbytes)
  324. def eof_received(self):
  325. """Called when the other end of the low-level stream
  326. is half-closed.
  327. If this returns a false value (including None), the transport
  328. will close itself. If it returns a true value, closing the
  329. transport is up to the protocol.
  330. """
  331. try:
  332. if self._loop.get_debug():
  333. aio_logger.debug("%r received EOF", self)
  334. if self._state == DO_HANDSHAKE:
  335. self._on_handshake_complete(ConnectionResetError)
  336. elif self._state == WRAPPED or self._state == FLUSHING:
  337. # We treat a low-level EOF as a critical situation similar to a
  338. # broken connection - just send whatever is in the buffer and
  339. # close. No application level eof_received() is called -
  340. # because we don't want the user to think that this is a
  341. # graceful shutdown triggered by SSL "close_notify".
  342. self._set_state(SHUTDOWN)
  343. self._on_shutdown_complete(None)
  344. elif self._state == SHUTDOWN:
  345. self._on_shutdown_complete(None)
  346. except Exception:
  347. self._transport.close()
  348. raise
  349. cdef _get_extra_info(self, name, default=None):
  350. if name == 'uvloop.sslproto':
  351. return self
  352. elif name in self._extra:
  353. return self._extra[name]
  354. elif self._transport is not None:
  355. return self._transport.get_extra_info(name, default)
  356. else:
  357. return default
  358. cdef _set_state(self, SSLProtocolState new_state):
  359. cdef bint allowed = False
  360. if new_state == UNWRAPPED:
  361. allowed = True
  362. elif self._state == UNWRAPPED and new_state == DO_HANDSHAKE:
  363. allowed = True
  364. elif self._state == DO_HANDSHAKE and new_state == WRAPPED:
  365. allowed = True
  366. elif self._state == WRAPPED and new_state == FLUSHING:
  367. allowed = True
  368. elif self._state == WRAPPED and new_state == SHUTDOWN:
  369. allowed = True
  370. elif self._state == FLUSHING and new_state == SHUTDOWN:
  371. allowed = True
  372. if allowed:
  373. self._state = new_state
  374. else:
  375. raise RuntimeError(
  376. 'cannot switch state from {} to {}'.format(
  377. self._state, new_state))
  378. # Handshake flow
  379. cdef _start_handshake(self):
  380. if self._loop.get_debug():
  381. aio_logger.debug("%r starts SSL handshake", self)
  382. self._handshake_start_time = self._loop.time()
  383. else:
  384. self._handshake_start_time = None
  385. self._set_state(DO_HANDSHAKE)
  386. # start handshake timeout count down
  387. self._handshake_timeout_handle = \
  388. self._loop.call_later(self._ssl_handshake_timeout,
  389. lambda: self._check_handshake_timeout())
  390. try:
  391. self._sslobj = self._sslcontext.wrap_bio(
  392. self._incoming, self._outgoing,
  393. server_side=self._server_side,
  394. server_hostname=self._server_hostname)
  395. self._sslobj_read = self._sslobj.read
  396. self._sslobj_write = self._sslobj.write
  397. self._sslobj_pending = self._sslobj.pending
  398. except Exception as ex:
  399. self._on_handshake_complete(ex)
  400. else:
  401. self._do_handshake()
  402. cdef _check_handshake_timeout(self):
  403. if self._state == DO_HANDSHAKE:
  404. msg = (
  405. f"SSL handshake is taking longer than "
  406. f"{self._ssl_handshake_timeout} seconds: "
  407. f"aborting the connection"
  408. )
  409. self._fatal_error(ConnectionAbortedError(msg))
  410. cdef _do_handshake(self):
  411. try:
  412. self._sslobj.do_handshake()
  413. except ssl_SSLAgainErrors as exc:
  414. self._process_outgoing()
  415. except ssl_SSLError as exc:
  416. self._on_handshake_complete(exc)
  417. else:
  418. self._on_handshake_complete(None)
  419. cdef _on_handshake_complete(self, handshake_exc):
  420. if self._handshake_timeout_handle is not None:
  421. self._handshake_timeout_handle.cancel()
  422. self._handshake_timeout_handle = None
  423. sslobj = self._sslobj
  424. try:
  425. if handshake_exc is None:
  426. self._set_state(WRAPPED)
  427. else:
  428. raise handshake_exc
  429. peercert = sslobj.getpeercert()
  430. except Exception as exc:
  431. self._set_state(UNWRAPPED)
  432. if isinstance(exc, ssl_CertificateError):
  433. msg = 'SSL handshake failed on verifying the certificate'
  434. else:
  435. msg = 'SSL handshake failed'
  436. self._fatal_error(exc, msg)
  437. self._wakeup_waiter(exc)
  438. return
  439. if self._loop.get_debug():
  440. dt = self._loop.time() - self._handshake_start_time
  441. aio_logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3)
  442. # Add extra info that becomes available after handshake.
  443. self._extra.update(peercert=peercert,
  444. cipher=sslobj.cipher(),
  445. compression=sslobj.compression(),
  446. ssl_object=sslobj)
  447. if self._app_state == STATE_INIT:
  448. self._app_state = STATE_CON_MADE
  449. self._app_protocol.connection_made(self._get_app_transport())
  450. self._wakeup_waiter()
  451. # We should wakeup user code before sending the first data below. In
  452. # case of `start_tls()`, the user can only get the SSLTransport in the
  453. # wakeup callback, because `connection_made()` is not called again.
  454. # We should schedule the first data later than the wakeup callback so
  455. # that the user get a chance to e.g. check ALPN with the transport
  456. # before having to handle the first data.
  457. self._loop._call_soon_handle(
  458. new_MethodHandle(self._loop,
  459. "SSLProtocol._do_read",
  460. <method_t> self._do_read,
  461. None, # current context is good
  462. self))
  463. # Shutdown flow
  464. cdef _start_shutdown(self, object context=None):
  465. if self._state in (FLUSHING, SHUTDOWN, UNWRAPPED):
  466. return
  467. # we don't need the context for _abort or the timeout, because
  468. # TCP transport._force_close() should be able to call
  469. # connection_lost() in the right context
  470. if self._app_transport is not None:
  471. self._app_transport._closed = True
  472. if self._state == DO_HANDSHAKE:
  473. self._abort(None)
  474. else:
  475. self._set_state(FLUSHING)
  476. self._shutdown_timeout_handle = \
  477. self._loop.call_later(self._ssl_shutdown_timeout,
  478. lambda: self._check_shutdown_timeout())
  479. self._do_flush(context)
  480. cdef _check_shutdown_timeout(self):
  481. if self._state in (FLUSHING, SHUTDOWN):
  482. self._transport._force_close(
  483. aio_TimeoutError('SSL shutdown timed out'))
  484. cdef _do_read_into_void(self, object context):
  485. """Consume and discard incoming application data.
  486. If close_notify is received for the first time, call eof_received.
  487. """
  488. cdef:
  489. bint close_notify = False
  490. try:
  491. while True:
  492. if not self._sslobj_read(SSL_READ_MAX_SIZE):
  493. close_notify = True
  494. break
  495. except ssl_SSLAgainErrors as exc:
  496. pass
  497. except ssl_SSLZeroReturnError:
  498. close_notify = True
  499. if close_notify:
  500. self._call_eof_received(context)
  501. cdef _do_flush(self, object context=None):
  502. """Flush the write backlog, discarding new data received.
  503. We don't send close_notify in FLUSHING because we still want to send
  504. the remaining data over SSL, even if we received a close_notify. Also,
  505. no application-level resume_writing() or pause_writing() will be called
  506. in FLUSHING, as we could fully manage the flow control internally.
  507. """
  508. try:
  509. self._do_read_into_void(context)
  510. self._do_write()
  511. self._process_outgoing()
  512. self._control_ssl_reading()
  513. except Exception as ex:
  514. self._on_shutdown_complete(ex)
  515. else:
  516. if not self._get_write_buffer_size():
  517. self._set_state(SHUTDOWN)
  518. self._do_shutdown(context)
  519. cdef _do_shutdown(self, object context=None):
  520. """Send close_notify and wait for the same from the peer."""
  521. try:
  522. # we must skip all application data (if any) before unwrap
  523. self._do_read_into_void(context)
  524. try:
  525. self._sslobj.unwrap()
  526. except ssl_SSLAgainErrors as exc:
  527. self._process_outgoing()
  528. else:
  529. self._process_outgoing()
  530. if not self._get_write_buffer_size():
  531. self._on_shutdown_complete(None)
  532. except Exception as ex:
  533. self._on_shutdown_complete(ex)
  534. cdef _on_shutdown_complete(self, shutdown_exc):
  535. if self._shutdown_timeout_handle is not None:
  536. self._shutdown_timeout_handle.cancel()
  537. self._shutdown_timeout_handle = None
  538. # we don't need the context here because TCP transport.close() should
  539. # be able to call connection_made() in the right context
  540. if shutdown_exc:
  541. self._fatal_error(shutdown_exc, 'Error occurred during shutdown')
  542. else:
  543. self._transport.close()
  544. cdef _abort(self, exc):
  545. self._set_state(UNWRAPPED)
  546. if self._transport is not None:
  547. self._transport._force_close(exc)
  548. # Outgoing flow
  549. cdef _write_appdata(self, list_of_data, object context):
  550. if self._state in (FLUSHING, SHUTDOWN, UNWRAPPED):
  551. if self._conn_lost >= LOG_THRESHOLD_FOR_CONNLOST_WRITES:
  552. aio_logger.warning('SSL connection is closed')
  553. self._conn_lost += 1
  554. return
  555. for data in list_of_data:
  556. self._write_backlog.append(data)
  557. self._write_buffer_size += len(data)
  558. try:
  559. if self._state == WRAPPED:
  560. self._do_write()
  561. self._process_outgoing()
  562. self._control_app_writing(context)
  563. except Exception as ex:
  564. self._fatal_error(ex, 'Fatal error on SSL protocol')
  565. cdef _do_write(self):
  566. """Do SSL write, consumes write backlog and fills outgoing BIO."""
  567. cdef size_t data_len, count
  568. try:
  569. while self._write_backlog:
  570. data = self._write_backlog[0]
  571. count = self._sslobj_write(data)
  572. data_len = len(data)
  573. if count < data_len:
  574. if not PyMemoryView_Check(data):
  575. data = PyMemoryView_FromObject(data)
  576. self._write_backlog[0] = data[count:]
  577. self._write_buffer_size -= count
  578. else:
  579. del self._write_backlog[0]
  580. self._write_buffer_size -= data_len
  581. except ssl_SSLAgainErrors as exc:
  582. pass
  583. cdef _process_outgoing(self):
  584. """Send bytes from the outgoing BIO."""
  585. if not self._ssl_writing_paused:
  586. data = self._outgoing_read()
  587. if len(data):
  588. if isinstance(self._transport, UVStream):
  589. (<UVStream>self._transport).write(data)
  590. else:
  591. self._transport.write(data)
  592. # Incoming flow
  593. cdef _do_read(self):
  594. if self._state != WRAPPED:
  595. return
  596. try:
  597. if not self._app_reading_paused:
  598. if self._app_protocol_is_buffer:
  599. self._do_read__buffered()
  600. else:
  601. self._do_read__copied()
  602. if self._write_backlog:
  603. self._do_write()
  604. self._process_outgoing()
  605. self._control_app_writing()
  606. self._control_ssl_reading()
  607. except Exception as ex:
  608. self._fatal_error(ex, 'Fatal error on SSL protocol')
  609. cdef _do_read__buffered(self):
  610. cdef:
  611. Py_ssize_t total_pending = (<Py_ssize_t>self._incoming.pending
  612. + <Py_ssize_t>self._sslobj_pending())
  613. # Ask for a little extra in case when decrypted data is bigger
  614. # than original
  615. object app_buffer = self._app_protocol_get_buffer(
  616. total_pending + 256)
  617. Py_ssize_t app_buffer_size = len(app_buffer)
  618. if app_buffer_size == 0:
  619. return
  620. cdef:
  621. Py_ssize_t last_bytes_read = -1
  622. Py_ssize_t total_bytes_read = 0
  623. Py_buffer pybuf
  624. bint pybuf_initialized = False
  625. try:
  626. # SSLObject.read may not return all available data in one go.
  627. # We have to keep calling read until it throw SSLWantReadError.
  628. # However, throwing SSLWantReadError is very expensive even in
  629. # the master trunk of cpython.
  630. # See https://github.com/python/cpython/issues/123954
  631. # One way to reduce reliance on SSLWantReadError is to check
  632. # self._incoming.pending > 0 and SSLObject.pending() > 0.
  633. # SSLObject.read may still throw SSLWantReadError even when
  634. # self._incoming.pending > 0 and SSLObject.pending() == 0,
  635. # but this should happen relatively rarely, only when ssl frame
  636. # is partially received.
  637. # This optimization works really well especially for peers
  638. # exchanging small messages and wanting to have minimal latency.
  639. # self._incoming.pending means how much data hasn't
  640. # been processed by ssl yet (read: "still encrypted"). The final
  641. # unencrypted data size maybe different.
  642. # self._sslobj.pending() means how much data has been already
  643. # decrypted and can be directly read with SSLObject.read.
  644. # Run test_create_server_ssl_over_ssl to reproduce different cases
  645. # for this method.
  646. while total_pending > 0:
  647. if total_bytes_read > 0:
  648. if not pybuf_initialized:
  649. PyObject_GetBuffer(app_buffer, &pybuf, PyBUF_WRITABLE)
  650. pybuf_initialized = True
  651. app_buffer = PyMemoryView_FromMemory(
  652. (<char*>pybuf.buf) + total_bytes_read,
  653. app_buffer_size - total_bytes_read,
  654. PyBUF_WRITE)
  655. last_bytes_read = <Py_ssize_t>self._sslobj_read(
  656. app_buffer_size - total_bytes_read, app_buffer)
  657. total_bytes_read += last_bytes_read
  658. if last_bytes_read == 0:
  659. break
  660. # User buffer may not fit all available data.
  661. if total_bytes_read == app_buffer_size:
  662. self._loop._call_soon_handle(
  663. new_MethodHandle(self._loop,
  664. "SSLProtocol._do_read",
  665. <method_t> self._do_read,
  666. None, # current context is good
  667. self))
  668. break
  669. total_pending = (<Py_ssize_t>self._incoming.pending +
  670. <Py_ssize_t>self._sslobj_pending())
  671. except ssl_SSLAgainErrors as exc:
  672. pass
  673. finally:
  674. if pybuf_initialized:
  675. PyBuffer_Release(&pybuf)
  676. if total_bytes_read > 0:
  677. self._app_protocol_buffer_updated(total_bytes_read)
  678. # SSLObject.read() may return 0 instead of throwing SSLWantReadError
  679. # This indicates that we reached EOF
  680. if last_bytes_read == 0:
  681. # close_notify
  682. self._call_eof_received()
  683. self._start_shutdown()
  684. cdef _do_read__copied(self):
  685. cdef:
  686. list data
  687. bytes first, chunk = b'1'
  688. bint zero = True, one = False
  689. try:
  690. while (<Py_ssize_t>self._incoming.pending > 0 or
  691. <Py_ssize_t>self._sslobj_pending() > 0):
  692. chunk = self._sslobj_read(SSL_READ_MAX_SIZE)
  693. if not chunk:
  694. break
  695. if zero:
  696. zero = False
  697. one = True
  698. first = chunk
  699. elif one:
  700. one = False
  701. data = [first, chunk]
  702. else:
  703. data.append(chunk)
  704. except ssl_SSLAgainErrors as exc:
  705. pass
  706. if one:
  707. self._app_protocol.data_received(first)
  708. elif not zero:
  709. self._app_protocol.data_received(b''.join(data))
  710. if not chunk:
  711. # close_notify
  712. self._call_eof_received()
  713. self._start_shutdown()
  714. cdef _call_eof_received(self, object context=None):
  715. if self._app_state == STATE_CON_MADE:
  716. self._app_state = STATE_EOF
  717. try:
  718. if context is None:
  719. # If the caller didn't provide a context, we assume the
  720. # caller is already in the right context, which is usually
  721. # inside the upstream callbacks like buffer_updated()
  722. keep_open = self._app_protocol.eof_received()
  723. else:
  724. keep_open = run_in_context(
  725. context, self._app_protocol.eof_received,
  726. )
  727. except (KeyboardInterrupt, SystemExit):
  728. raise
  729. except BaseException as ex:
  730. self._fatal_error(ex, 'Error calling eof_received()')
  731. else:
  732. if keep_open:
  733. aio_logger.warning('returning true from eof_received() '
  734. 'has no effect when using ssl')
  735. # Flow control for writes from APP socket
  736. cdef _control_app_writing(self, object context=None):
  737. cdef size_t size = self._get_write_buffer_size()
  738. if size >= self._outgoing_high_water and not self._app_writing_paused:
  739. self._app_writing_paused = True
  740. try:
  741. if context is None:
  742. # If the caller didn't provide a context, we assume the
  743. # caller is already in the right context, which is usually
  744. # inside the upstream callbacks like buffer_updated()
  745. self._app_protocol.pause_writing()
  746. else:
  747. run_in_context(context, self._app_protocol.pause_writing)
  748. except (KeyboardInterrupt, SystemExit):
  749. raise
  750. except BaseException as exc:
  751. self._loop.call_exception_handler({
  752. 'message': 'protocol.pause_writing() failed',
  753. 'exception': exc,
  754. 'transport': self._app_transport,
  755. 'protocol': self,
  756. })
  757. elif size <= self._outgoing_low_water and self._app_writing_paused:
  758. self._app_writing_paused = False
  759. try:
  760. if context is None:
  761. # If the caller didn't provide a context, we assume the
  762. # caller is already in the right context, which is usually
  763. # inside the upstream callbacks like resume_writing()
  764. self._app_protocol.resume_writing()
  765. else:
  766. run_in_context(context, self._app_protocol.resume_writing)
  767. except (KeyboardInterrupt, SystemExit):
  768. raise
  769. except BaseException as exc:
  770. self._loop.call_exception_handler({
  771. 'message': 'protocol.resume_writing() failed',
  772. 'exception': exc,
  773. 'transport': self._app_transport,
  774. 'protocol': self,
  775. })
  776. cdef size_t _get_write_buffer_size(self):
  777. return self._outgoing.pending + self._write_buffer_size
  778. cdef _set_write_buffer_limits(self, high=None, low=None):
  779. high, low = add_flowcontrol_defaults(
  780. high, low, FLOW_CONTROL_HIGH_WATER_SSL_WRITE)
  781. self._outgoing_high_water = high
  782. self._outgoing_low_water = low
  783. # Flow control for reads to APP socket
  784. cdef _pause_reading(self):
  785. self._app_reading_paused = True
  786. cdef _resume_reading(self, object context):
  787. if self._app_reading_paused:
  788. self._app_reading_paused = False
  789. if self._state == WRAPPED:
  790. self._loop._call_soon_handle(
  791. new_MethodHandle(self._loop,
  792. "SSLProtocol._do_read",
  793. <method_t>self._do_read,
  794. context,
  795. self))
  796. # Flow control for reads from SSL socket
  797. cdef _control_ssl_reading(self):
  798. cdef size_t size = self._get_read_buffer_size()
  799. if size >= self._incoming_high_water and not self._ssl_reading_paused:
  800. self._ssl_reading_paused = True
  801. self._transport.pause_reading()
  802. elif size <= self._incoming_low_water and self._ssl_reading_paused:
  803. self._ssl_reading_paused = False
  804. self._transport.resume_reading()
  805. cdef _set_read_buffer_limits(self, high=None, low=None):
  806. high, low = add_flowcontrol_defaults(
  807. high, low, FLOW_CONTROL_HIGH_WATER_SSL_READ)
  808. self._incoming_high_water = high
  809. self._incoming_low_water = low
  810. cdef size_t _get_read_buffer_size(self):
  811. return self._incoming.pending
  812. # Flow control for writes to SSL socket
  813. def pause_writing(self):
  814. """Called when the low-level transport's buffer goes over
  815. the high-water mark.
  816. """
  817. assert not self._ssl_writing_paused
  818. self._ssl_writing_paused = True
  819. def resume_writing(self):
  820. """Called when the low-level transport's buffer drains below
  821. the low-water mark.
  822. """
  823. assert self._ssl_writing_paused
  824. self._ssl_writing_paused = False
  825. if self._state == WRAPPED:
  826. self._process_outgoing()
  827. self._control_app_writing()
  828. elif self._state == FLUSHING:
  829. self._do_flush()
  830. elif self._state == SHUTDOWN:
  831. self._do_shutdown()
  832. cdef _fatal_error(self, exc, message='Fatal error on transport'):
  833. if self._app_transport:
  834. self._app_transport._force_close(exc)
  835. elif self._transport:
  836. self._transport._force_close(exc)
  837. if isinstance(exc, OSError):
  838. if self._loop.get_debug():
  839. aio_logger.debug("%r: %s", self, message, exc_info=True)
  840. elif not isinstance(exc, aio_CancelledError):
  841. self._loop.call_exception_handler({
  842. 'message': message,
  843. 'exception': exc,
  844. 'transport': self._transport,
  845. 'protocol': self,
  846. })