@@ -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
@@ -700,6 +703,7 @@ def _write_appdata(self, list_of_data):
700703 self ._fatal_error (ex , 'Fatal error on SSL protocol' )
701704
702705 def _do_write (self ):
706+ pending = self ._outgoing .pending
703707 try :
704708 while self ._write_backlog :
705709 data = self ._write_backlog [0 ]
@@ -713,11 +717,13 @@ def _do_write(self):
713717 self ._write_buffer_size -= data_len
714718 except SSLAgainErrors :
715719 pass
720+ self ._outgoing_app_size += self ._outgoing .pending - pending
716721 self ._process_outgoing ()
717722
718723 def _process_outgoing (self ):
719724 if not self ._ssl_writing_paused :
720725 data = self ._outgoing .read ()
726+ self ._outgoing_app_size = 0
721727 if len (data ):
722728 self ._transport .write (data )
723729 self ._control_app_writing ()
@@ -879,7 +885,15 @@ def resume():
879885 # Flow control for reads from SSL socket
880886
881887 def _control_ssl_reading (self ):
882- size = self ._get_read_buffer_size ()
888+ # Also count the records OpenSSL writes on its own while reading
889+ # (alerts, KeyUpdate replies, ...) which the peer does not read:
890+ # the app is not involved in producing them, so pausing it does
891+ # not bound them; only pausing reads from the peer does. Whatever
892+ # was produced while writing app data (_outgoing_app_size) is left
893+ # out so that two peers which both write before they read cannot
894+ # deadlock.
895+ size = (self ._get_read_buffer_size () +
896+ self ._outgoing .pending - self ._outgoing_app_size )
883897 if size >= self ._incoming_high_water and not self ._ssl_reading_paused :
884898 self ._ssl_reading_paused = True
885899 self ._transport .pause_reading ()
@@ -912,6 +926,7 @@ def resume_writing(self):
912926 assert self ._ssl_writing_paused
913927 self ._ssl_writing_paused = False
914928 self ._process_outgoing ()
929+ self ._control_ssl_reading ()
915930
916931 def _fatal_error (self , exc , message = 'Fatal error on transport' ):
917932 if self ._transport :
0 commit comments