@@ -308,6 +308,9 @@ def __init__(self, loop, app_protocol, sslcontext, waiter,
308308 # App data write buffering
309309 self ._write_backlog = collections .deque ()
310310 self ._write_buffer_size = 0
311+ # How much of self._outgoing was produced by _do_write(): encrypted
312+ # app data, plus anything else OpenSSL flushed along with it
313+ self ._outgoing_app_size = 0
311314
312315 self ._waiter = waiter
313316 self ._loop = loop
@@ -697,6 +700,7 @@ def _write_appdata(self, list_of_data):
697700 self ._fatal_error (ex , 'Fatal error on SSL protocol' )
698701
699702 def _do_write (self ):
703+ pending = self ._outgoing .pending
700704 try :
701705 while self ._write_backlog :
702706 data = self ._write_backlog [0 ]
@@ -710,11 +714,13 @@ def _do_write(self):
710714 self ._write_buffer_size -= data_len
711715 except SSLAgainErrors :
712716 pass
717+ self ._outgoing_app_size += self ._outgoing .pending - pending
713718 self ._process_outgoing ()
714719
715720 def _process_outgoing (self ):
716721 if not self ._ssl_writing_paused :
717722 data = self ._outgoing .read ()
723+ self ._outgoing_app_size = 0
718724 if len (data ):
719725 self ._transport .write (data )
720726 self ._control_app_writing ()
@@ -876,7 +882,15 @@ def resume():
876882 # Flow control for reads from SSL socket
877883
878884 def _control_ssl_reading (self ):
879- size = self ._get_read_buffer_size ()
885+ # Also count the records OpenSSL writes on its own while reading
886+ # (alerts, KeyUpdate replies, ...) which the peer does not read:
887+ # the app is not involved in producing them, so pausing it does
888+ # not bound them; only pausing reads from the peer does. Whatever
889+ # was produced while writing app data (_outgoing_app_size) is left
890+ # out so that two peers which both write before they read cannot
891+ # deadlock.
892+ size = (self ._get_read_buffer_size () +
893+ self ._outgoing .pending - self ._outgoing_app_size )
880894 if size >= self ._incoming_high_water and not self ._ssl_reading_paused :
881895 self ._ssl_reading_paused = True
882896 self ._transport .pause_reading ()
@@ -909,6 +923,7 @@ def resume_writing(self):
909923 assert self ._ssl_writing_paused
910924 self ._ssl_writing_paused = False
911925 self ._process_outgoing ()
926+ self ._control_ssl_reading ()
912927
913928 def _fatal_error (self , exc , message = 'Fatal error on transport' ):
914929 if self ._transport :
0 commit comments