1*cda5da8dSAndroid Build Coastguard Workerimport collections 2*cda5da8dSAndroid Build Coastguard Workerimport enum 3*cda5da8dSAndroid Build Coastguard Workerimport warnings 4*cda5da8dSAndroid Build Coastguard Workertry: 5*cda5da8dSAndroid Build Coastguard Worker import ssl 6*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: # pragma: no cover 7*cda5da8dSAndroid Build Coastguard Worker ssl = None 8*cda5da8dSAndroid Build Coastguard Worker 9*cda5da8dSAndroid Build Coastguard Workerfrom . import constants 10*cda5da8dSAndroid Build Coastguard Workerfrom . import exceptions 11*cda5da8dSAndroid Build Coastguard Workerfrom . import protocols 12*cda5da8dSAndroid Build Coastguard Workerfrom . import transports 13*cda5da8dSAndroid Build Coastguard Workerfrom .log import logger 14*cda5da8dSAndroid Build Coastguard Worker 15*cda5da8dSAndroid Build Coastguard Workerif ssl is not None: 16*cda5da8dSAndroid Build Coastguard Worker SSLAgainErrors = (ssl.SSLWantReadError, ssl.SSLSyscallError) 17*cda5da8dSAndroid Build Coastguard Worker 18*cda5da8dSAndroid Build Coastguard Worker 19*cda5da8dSAndroid Build Coastguard Workerclass SSLProtocolState(enum.Enum): 20*cda5da8dSAndroid Build Coastguard Worker UNWRAPPED = "UNWRAPPED" 21*cda5da8dSAndroid Build Coastguard Worker DO_HANDSHAKE = "DO_HANDSHAKE" 22*cda5da8dSAndroid Build Coastguard Worker WRAPPED = "WRAPPED" 23*cda5da8dSAndroid Build Coastguard Worker FLUSHING = "FLUSHING" 24*cda5da8dSAndroid Build Coastguard Worker SHUTDOWN = "SHUTDOWN" 25*cda5da8dSAndroid Build Coastguard Worker 26*cda5da8dSAndroid Build Coastguard Worker 27*cda5da8dSAndroid Build Coastguard Workerclass AppProtocolState(enum.Enum): 28*cda5da8dSAndroid Build Coastguard Worker # This tracks the state of app protocol (https://git.io/fj59P): 29*cda5da8dSAndroid Build Coastguard Worker # 30*cda5da8dSAndroid Build Coastguard Worker # INIT -cm-> CON_MADE [-dr*->] [-er-> EOF?] -cl-> CON_LOST 31*cda5da8dSAndroid Build Coastguard Worker # 32*cda5da8dSAndroid Build Coastguard Worker # * cm: connection_made() 33*cda5da8dSAndroid Build Coastguard Worker # * dr: data_received() 34*cda5da8dSAndroid Build Coastguard Worker # * er: eof_received() 35*cda5da8dSAndroid Build Coastguard Worker # * cl: connection_lost() 36*cda5da8dSAndroid Build Coastguard Worker 37*cda5da8dSAndroid Build Coastguard Worker STATE_INIT = "STATE_INIT" 38*cda5da8dSAndroid Build Coastguard Worker STATE_CON_MADE = "STATE_CON_MADE" 39*cda5da8dSAndroid Build Coastguard Worker STATE_EOF = "STATE_EOF" 40*cda5da8dSAndroid Build Coastguard Worker STATE_CON_LOST = "STATE_CON_LOST" 41*cda5da8dSAndroid Build Coastguard Worker 42*cda5da8dSAndroid Build Coastguard Worker 43*cda5da8dSAndroid Build Coastguard Workerdef _create_transport_context(server_side, server_hostname): 44*cda5da8dSAndroid Build Coastguard Worker if server_side: 45*cda5da8dSAndroid Build Coastguard Worker raise ValueError('Server side SSL needs a valid SSLContext') 46*cda5da8dSAndroid Build Coastguard Worker 47*cda5da8dSAndroid Build Coastguard Worker # Client side may pass ssl=True to use a default 48*cda5da8dSAndroid Build Coastguard Worker # context; in that case the sslcontext passed is None. 49*cda5da8dSAndroid Build Coastguard Worker # The default is secure for client connections. 50*cda5da8dSAndroid Build Coastguard Worker # Python 3.4+: use up-to-date strong settings. 51*cda5da8dSAndroid Build Coastguard Worker sslcontext = ssl.create_default_context() 52*cda5da8dSAndroid Build Coastguard Worker if not server_hostname: 53*cda5da8dSAndroid Build Coastguard Worker sslcontext.check_hostname = False 54*cda5da8dSAndroid Build Coastguard Worker return sslcontext 55*cda5da8dSAndroid Build Coastguard Worker 56*cda5da8dSAndroid Build Coastguard Worker 57*cda5da8dSAndroid Build Coastguard Workerdef add_flowcontrol_defaults(high, low, kb): 58*cda5da8dSAndroid Build Coastguard Worker if high is None: 59*cda5da8dSAndroid Build Coastguard Worker if low is None: 60*cda5da8dSAndroid Build Coastguard Worker hi = kb * 1024 61*cda5da8dSAndroid Build Coastguard Worker else: 62*cda5da8dSAndroid Build Coastguard Worker lo = low 63*cda5da8dSAndroid Build Coastguard Worker hi = 4 * lo 64*cda5da8dSAndroid Build Coastguard Worker else: 65*cda5da8dSAndroid Build Coastguard Worker hi = high 66*cda5da8dSAndroid Build Coastguard Worker if low is None: 67*cda5da8dSAndroid Build Coastguard Worker lo = hi // 4 68*cda5da8dSAndroid Build Coastguard Worker else: 69*cda5da8dSAndroid Build Coastguard Worker lo = low 70*cda5da8dSAndroid Build Coastguard Worker 71*cda5da8dSAndroid Build Coastguard Worker if not hi >= lo >= 0: 72*cda5da8dSAndroid Build Coastguard Worker raise ValueError('high (%r) must be >= low (%r) must be >= 0' % 73*cda5da8dSAndroid Build Coastguard Worker (hi, lo)) 74*cda5da8dSAndroid Build Coastguard Worker 75*cda5da8dSAndroid Build Coastguard Worker return hi, lo 76*cda5da8dSAndroid Build Coastguard Worker 77*cda5da8dSAndroid Build Coastguard Worker 78*cda5da8dSAndroid Build Coastguard Workerclass _SSLProtocolTransport(transports._FlowControlMixin, 79*cda5da8dSAndroid Build Coastguard Worker transports.Transport): 80*cda5da8dSAndroid Build Coastguard Worker 81*cda5da8dSAndroid Build Coastguard Worker _start_tls_compatible = True 82*cda5da8dSAndroid Build Coastguard Worker _sendfile_compatible = constants._SendfileMode.FALLBACK 83*cda5da8dSAndroid Build Coastguard Worker 84*cda5da8dSAndroid Build Coastguard Worker def __init__(self, loop, ssl_protocol): 85*cda5da8dSAndroid Build Coastguard Worker self._loop = loop 86*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol = ssl_protocol 87*cda5da8dSAndroid Build Coastguard Worker self._closed = False 88*cda5da8dSAndroid Build Coastguard Worker 89*cda5da8dSAndroid Build Coastguard Worker def get_extra_info(self, name, default=None): 90*cda5da8dSAndroid Build Coastguard Worker """Get optional transport information.""" 91*cda5da8dSAndroid Build Coastguard Worker return self._ssl_protocol._get_extra_info(name, default) 92*cda5da8dSAndroid Build Coastguard Worker 93*cda5da8dSAndroid Build Coastguard Worker def set_protocol(self, protocol): 94*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._set_app_protocol(protocol) 95*cda5da8dSAndroid Build Coastguard Worker 96*cda5da8dSAndroid Build Coastguard Worker def get_protocol(self): 97*cda5da8dSAndroid Build Coastguard Worker return self._ssl_protocol._app_protocol 98*cda5da8dSAndroid Build Coastguard Worker 99*cda5da8dSAndroid Build Coastguard Worker def is_closing(self): 100*cda5da8dSAndroid Build Coastguard Worker return self._closed 101*cda5da8dSAndroid Build Coastguard Worker 102*cda5da8dSAndroid Build Coastguard Worker def close(self): 103*cda5da8dSAndroid Build Coastguard Worker """Close the transport. 104*cda5da8dSAndroid Build Coastguard Worker 105*cda5da8dSAndroid Build Coastguard Worker Buffered data will be flushed asynchronously. No more data 106*cda5da8dSAndroid Build Coastguard Worker will be received. After all buffered data is flushed, the 107*cda5da8dSAndroid Build Coastguard Worker protocol's connection_lost() method will (eventually) called 108*cda5da8dSAndroid Build Coastguard Worker with None as its argument. 109*cda5da8dSAndroid Build Coastguard Worker """ 110*cda5da8dSAndroid Build Coastguard Worker if not self._closed: 111*cda5da8dSAndroid Build Coastguard Worker self._closed = True 112*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._start_shutdown() 113*cda5da8dSAndroid Build Coastguard Worker else: 114*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol = None 115*cda5da8dSAndroid Build Coastguard Worker 116*cda5da8dSAndroid Build Coastguard Worker def __del__(self, _warnings=warnings): 117*cda5da8dSAndroid Build Coastguard Worker if not self._closed: 118*cda5da8dSAndroid Build Coastguard Worker self._closed = True 119*cda5da8dSAndroid Build Coastguard Worker _warnings.warn( 120*cda5da8dSAndroid Build Coastguard Worker "unclosed transport <asyncio._SSLProtocolTransport " 121*cda5da8dSAndroid Build Coastguard Worker "object>", ResourceWarning) 122*cda5da8dSAndroid Build Coastguard Worker 123*cda5da8dSAndroid Build Coastguard Worker def is_reading(self): 124*cda5da8dSAndroid Build Coastguard Worker return not self._ssl_protocol._app_reading_paused 125*cda5da8dSAndroid Build Coastguard Worker 126*cda5da8dSAndroid Build Coastguard Worker def pause_reading(self): 127*cda5da8dSAndroid Build Coastguard Worker """Pause the receiving end. 128*cda5da8dSAndroid Build Coastguard Worker 129*cda5da8dSAndroid Build Coastguard Worker No data will be passed to the protocol's data_received() 130*cda5da8dSAndroid Build Coastguard Worker method until resume_reading() is called. 131*cda5da8dSAndroid Build Coastguard Worker """ 132*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._pause_reading() 133*cda5da8dSAndroid Build Coastguard Worker 134*cda5da8dSAndroid Build Coastguard Worker def resume_reading(self): 135*cda5da8dSAndroid Build Coastguard Worker """Resume the receiving end. 136*cda5da8dSAndroid Build Coastguard Worker 137*cda5da8dSAndroid Build Coastguard Worker Data received will once again be passed to the protocol's 138*cda5da8dSAndroid Build Coastguard Worker data_received() method. 139*cda5da8dSAndroid Build Coastguard Worker """ 140*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._resume_reading() 141*cda5da8dSAndroid Build Coastguard Worker 142*cda5da8dSAndroid Build Coastguard Worker def set_write_buffer_limits(self, high=None, low=None): 143*cda5da8dSAndroid Build Coastguard Worker """Set the high- and low-water limits for write flow control. 144*cda5da8dSAndroid Build Coastguard Worker 145*cda5da8dSAndroid Build Coastguard Worker These two values control when to call the protocol's 146*cda5da8dSAndroid Build Coastguard Worker pause_writing() and resume_writing() methods. If specified, 147*cda5da8dSAndroid Build Coastguard Worker the low-water limit must be less than or equal to the 148*cda5da8dSAndroid Build Coastguard Worker high-water limit. Neither value can be negative. 149*cda5da8dSAndroid Build Coastguard Worker 150*cda5da8dSAndroid Build Coastguard Worker The defaults are implementation-specific. If only the 151*cda5da8dSAndroid Build Coastguard Worker high-water limit is given, the low-water limit defaults to an 152*cda5da8dSAndroid Build Coastguard Worker implementation-specific value less than or equal to the 153*cda5da8dSAndroid Build Coastguard Worker high-water limit. Setting high to zero forces low to zero as 154*cda5da8dSAndroid Build Coastguard Worker well, and causes pause_writing() to be called whenever the 155*cda5da8dSAndroid Build Coastguard Worker buffer becomes non-empty. Setting low to zero causes 156*cda5da8dSAndroid Build Coastguard Worker resume_writing() to be called only once the buffer is empty. 157*cda5da8dSAndroid Build Coastguard Worker Use of zero for either limit is generally sub-optimal as it 158*cda5da8dSAndroid Build Coastguard Worker reduces opportunities for doing I/O and computation 159*cda5da8dSAndroid Build Coastguard Worker concurrently. 160*cda5da8dSAndroid Build Coastguard Worker """ 161*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._set_write_buffer_limits(high, low) 162*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._control_app_writing() 163*cda5da8dSAndroid Build Coastguard Worker 164*cda5da8dSAndroid Build Coastguard Worker def get_write_buffer_limits(self): 165*cda5da8dSAndroid Build Coastguard Worker return (self._ssl_protocol._outgoing_low_water, 166*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._outgoing_high_water) 167*cda5da8dSAndroid Build Coastguard Worker 168*cda5da8dSAndroid Build Coastguard Worker def get_write_buffer_size(self): 169*cda5da8dSAndroid Build Coastguard Worker """Return the current size of the write buffers.""" 170*cda5da8dSAndroid Build Coastguard Worker return self._ssl_protocol._get_write_buffer_size() 171*cda5da8dSAndroid Build Coastguard Worker 172*cda5da8dSAndroid Build Coastguard Worker def set_read_buffer_limits(self, high=None, low=None): 173*cda5da8dSAndroid Build Coastguard Worker """Set the high- and low-water limits for read flow control. 174*cda5da8dSAndroid Build Coastguard Worker 175*cda5da8dSAndroid Build Coastguard Worker These two values control when to call the upstream transport's 176*cda5da8dSAndroid Build Coastguard Worker pause_reading() and resume_reading() methods. If specified, 177*cda5da8dSAndroid Build Coastguard Worker the low-water limit must be less than or equal to the 178*cda5da8dSAndroid Build Coastguard Worker high-water limit. Neither value can be negative. 179*cda5da8dSAndroid Build Coastguard Worker 180*cda5da8dSAndroid Build Coastguard Worker The defaults are implementation-specific. If only the 181*cda5da8dSAndroid Build Coastguard Worker high-water limit is given, the low-water limit defaults to an 182*cda5da8dSAndroid Build Coastguard Worker implementation-specific value less than or equal to the 183*cda5da8dSAndroid Build Coastguard Worker high-water limit. Setting high to zero forces low to zero as 184*cda5da8dSAndroid Build Coastguard Worker well, and causes pause_reading() to be called whenever the 185*cda5da8dSAndroid Build Coastguard Worker buffer becomes non-empty. Setting low to zero causes 186*cda5da8dSAndroid Build Coastguard Worker resume_reading() to be called only once the buffer is empty. 187*cda5da8dSAndroid Build Coastguard Worker Use of zero for either limit is generally sub-optimal as it 188*cda5da8dSAndroid Build Coastguard Worker reduces opportunities for doing I/O and computation 189*cda5da8dSAndroid Build Coastguard Worker concurrently. 190*cda5da8dSAndroid Build Coastguard Worker """ 191*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._set_read_buffer_limits(high, low) 192*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._control_ssl_reading() 193*cda5da8dSAndroid Build Coastguard Worker 194*cda5da8dSAndroid Build Coastguard Worker def get_read_buffer_limits(self): 195*cda5da8dSAndroid Build Coastguard Worker return (self._ssl_protocol._incoming_low_water, 196*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._incoming_high_water) 197*cda5da8dSAndroid Build Coastguard Worker 198*cda5da8dSAndroid Build Coastguard Worker def get_read_buffer_size(self): 199*cda5da8dSAndroid Build Coastguard Worker """Return the current size of the read buffer.""" 200*cda5da8dSAndroid Build Coastguard Worker return self._ssl_protocol._get_read_buffer_size() 201*cda5da8dSAndroid Build Coastguard Worker 202*cda5da8dSAndroid Build Coastguard Worker @property 203*cda5da8dSAndroid Build Coastguard Worker def _protocol_paused(self): 204*cda5da8dSAndroid Build Coastguard Worker # Required for sendfile fallback pause_writing/resume_writing logic 205*cda5da8dSAndroid Build Coastguard Worker return self._ssl_protocol._app_writing_paused 206*cda5da8dSAndroid Build Coastguard Worker 207*cda5da8dSAndroid Build Coastguard Worker def write(self, data): 208*cda5da8dSAndroid Build Coastguard Worker """Write some data bytes to the transport. 209*cda5da8dSAndroid Build Coastguard Worker 210*cda5da8dSAndroid Build Coastguard Worker This does not block; it buffers the data and arranges for it 211*cda5da8dSAndroid Build Coastguard Worker to be sent out asynchronously. 212*cda5da8dSAndroid Build Coastguard Worker """ 213*cda5da8dSAndroid Build Coastguard Worker if not isinstance(data, (bytes, bytearray, memoryview)): 214*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f"data: expecting a bytes-like instance, " 215*cda5da8dSAndroid Build Coastguard Worker f"got {type(data).__name__}") 216*cda5da8dSAndroid Build Coastguard Worker if not data: 217*cda5da8dSAndroid Build Coastguard Worker return 218*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._write_appdata((data,)) 219*cda5da8dSAndroid Build Coastguard Worker 220*cda5da8dSAndroid Build Coastguard Worker def writelines(self, list_of_data): 221*cda5da8dSAndroid Build Coastguard Worker """Write a list (or any iterable) of data bytes to the transport. 222*cda5da8dSAndroid Build Coastguard Worker 223*cda5da8dSAndroid Build Coastguard Worker The default implementation concatenates the arguments and 224*cda5da8dSAndroid Build Coastguard Worker calls write() on the result. 225*cda5da8dSAndroid Build Coastguard Worker """ 226*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._write_appdata(list_of_data) 227*cda5da8dSAndroid Build Coastguard Worker 228*cda5da8dSAndroid Build Coastguard Worker def write_eof(self): 229*cda5da8dSAndroid Build Coastguard Worker """Close the write end after flushing buffered data. 230*cda5da8dSAndroid Build Coastguard Worker 231*cda5da8dSAndroid Build Coastguard Worker This raises :exc:`NotImplementedError` right now. 232*cda5da8dSAndroid Build Coastguard Worker """ 233*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError 234*cda5da8dSAndroid Build Coastguard Worker 235*cda5da8dSAndroid Build Coastguard Worker def can_write_eof(self): 236*cda5da8dSAndroid Build Coastguard Worker """Return True if this transport supports write_eof(), False if not.""" 237*cda5da8dSAndroid Build Coastguard Worker return False 238*cda5da8dSAndroid Build Coastguard Worker 239*cda5da8dSAndroid Build Coastguard Worker def abort(self): 240*cda5da8dSAndroid Build Coastguard Worker """Close the transport immediately. 241*cda5da8dSAndroid Build Coastguard Worker 242*cda5da8dSAndroid Build Coastguard Worker Buffered data will be lost. No more data will be received. 243*cda5da8dSAndroid Build Coastguard Worker The protocol's connection_lost() method will (eventually) be 244*cda5da8dSAndroid Build Coastguard Worker called with None as its argument. 245*cda5da8dSAndroid Build Coastguard Worker """ 246*cda5da8dSAndroid Build Coastguard Worker self._closed = True 247*cda5da8dSAndroid Build Coastguard Worker if self._ssl_protocol is not None: 248*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._abort() 249*cda5da8dSAndroid Build Coastguard Worker 250*cda5da8dSAndroid Build Coastguard Worker def _force_close(self, exc): 251*cda5da8dSAndroid Build Coastguard Worker self._closed = True 252*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._abort(exc) 253*cda5da8dSAndroid Build Coastguard Worker 254*cda5da8dSAndroid Build Coastguard Worker def _test__append_write_backlog(self, data): 255*cda5da8dSAndroid Build Coastguard Worker # for test only 256*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._write_backlog.append(data) 257*cda5da8dSAndroid Build Coastguard Worker self._ssl_protocol._write_buffer_size += len(data) 258*cda5da8dSAndroid Build Coastguard Worker 259*cda5da8dSAndroid Build Coastguard Worker 260*cda5da8dSAndroid Build Coastguard Workerclass SSLProtocol(protocols.BufferedProtocol): 261*cda5da8dSAndroid Build Coastguard Worker max_size = 256 * 1024 # Buffer size passed to read() 262*cda5da8dSAndroid Build Coastguard Worker 263*cda5da8dSAndroid Build Coastguard Worker _handshake_start_time = None 264*cda5da8dSAndroid Build Coastguard Worker _handshake_timeout_handle = None 265*cda5da8dSAndroid Build Coastguard Worker _shutdown_timeout_handle = None 266*cda5da8dSAndroid Build Coastguard Worker 267*cda5da8dSAndroid Build Coastguard Worker def __init__(self, loop, app_protocol, sslcontext, waiter, 268*cda5da8dSAndroid Build Coastguard Worker server_side=False, server_hostname=None, 269*cda5da8dSAndroid Build Coastguard Worker call_connection_made=True, 270*cda5da8dSAndroid Build Coastguard Worker ssl_handshake_timeout=None, 271*cda5da8dSAndroid Build Coastguard Worker ssl_shutdown_timeout=None): 272*cda5da8dSAndroid Build Coastguard Worker if ssl is None: 273*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError("stdlib ssl module not available") 274*cda5da8dSAndroid Build Coastguard Worker 275*cda5da8dSAndroid Build Coastguard Worker self._ssl_buffer = bytearray(self.max_size) 276*cda5da8dSAndroid Build Coastguard Worker self._ssl_buffer_view = memoryview(self._ssl_buffer) 277*cda5da8dSAndroid Build Coastguard Worker 278*cda5da8dSAndroid Build Coastguard Worker if ssl_handshake_timeout is None: 279*cda5da8dSAndroid Build Coastguard Worker ssl_handshake_timeout = constants.SSL_HANDSHAKE_TIMEOUT 280*cda5da8dSAndroid Build Coastguard Worker elif ssl_handshake_timeout <= 0: 281*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 282*cda5da8dSAndroid Build Coastguard Worker f"ssl_handshake_timeout should be a positive number, " 283*cda5da8dSAndroid Build Coastguard Worker f"got {ssl_handshake_timeout}") 284*cda5da8dSAndroid Build Coastguard Worker if ssl_shutdown_timeout is None: 285*cda5da8dSAndroid Build Coastguard Worker ssl_shutdown_timeout = constants.SSL_SHUTDOWN_TIMEOUT 286*cda5da8dSAndroid Build Coastguard Worker elif ssl_shutdown_timeout <= 0: 287*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 288*cda5da8dSAndroid Build Coastguard Worker f"ssl_shutdown_timeout should be a positive number, " 289*cda5da8dSAndroid Build Coastguard Worker f"got {ssl_shutdown_timeout}") 290*cda5da8dSAndroid Build Coastguard Worker 291*cda5da8dSAndroid Build Coastguard Worker if not sslcontext: 292*cda5da8dSAndroid Build Coastguard Worker sslcontext = _create_transport_context( 293*cda5da8dSAndroid Build Coastguard Worker server_side, server_hostname) 294*cda5da8dSAndroid Build Coastguard Worker 295*cda5da8dSAndroid Build Coastguard Worker self._server_side = server_side 296*cda5da8dSAndroid Build Coastguard Worker if server_hostname and not server_side: 297*cda5da8dSAndroid Build Coastguard Worker self._server_hostname = server_hostname 298*cda5da8dSAndroid Build Coastguard Worker else: 299*cda5da8dSAndroid Build Coastguard Worker self._server_hostname = None 300*cda5da8dSAndroid Build Coastguard Worker self._sslcontext = sslcontext 301*cda5da8dSAndroid Build Coastguard Worker # SSL-specific extra info. More info are set when the handshake 302*cda5da8dSAndroid Build Coastguard Worker # completes. 303*cda5da8dSAndroid Build Coastguard Worker self._extra = dict(sslcontext=sslcontext) 304*cda5da8dSAndroid Build Coastguard Worker 305*cda5da8dSAndroid Build Coastguard Worker # App data write buffering 306*cda5da8dSAndroid Build Coastguard Worker self._write_backlog = collections.deque() 307*cda5da8dSAndroid Build Coastguard Worker self._write_buffer_size = 0 308*cda5da8dSAndroid Build Coastguard Worker 309*cda5da8dSAndroid Build Coastguard Worker self._waiter = waiter 310*cda5da8dSAndroid Build Coastguard Worker self._loop = loop 311*cda5da8dSAndroid Build Coastguard Worker self._set_app_protocol(app_protocol) 312*cda5da8dSAndroid Build Coastguard Worker self._app_transport = None 313*cda5da8dSAndroid Build Coastguard Worker self._app_transport_created = False 314*cda5da8dSAndroid Build Coastguard Worker # transport, ex: SelectorSocketTransport 315*cda5da8dSAndroid Build Coastguard Worker self._transport = None 316*cda5da8dSAndroid Build Coastguard Worker self._ssl_handshake_timeout = ssl_handshake_timeout 317*cda5da8dSAndroid Build Coastguard Worker self._ssl_shutdown_timeout = ssl_shutdown_timeout 318*cda5da8dSAndroid Build Coastguard Worker # SSL and state machine 319*cda5da8dSAndroid Build Coastguard Worker self._incoming = ssl.MemoryBIO() 320*cda5da8dSAndroid Build Coastguard Worker self._outgoing = ssl.MemoryBIO() 321*cda5da8dSAndroid Build Coastguard Worker self._state = SSLProtocolState.UNWRAPPED 322*cda5da8dSAndroid Build Coastguard Worker self._conn_lost = 0 # Set when connection_lost called 323*cda5da8dSAndroid Build Coastguard Worker if call_connection_made: 324*cda5da8dSAndroid Build Coastguard Worker self._app_state = AppProtocolState.STATE_INIT 325*cda5da8dSAndroid Build Coastguard Worker else: 326*cda5da8dSAndroid Build Coastguard Worker self._app_state = AppProtocolState.STATE_CON_MADE 327*cda5da8dSAndroid Build Coastguard Worker self._sslobj = self._sslcontext.wrap_bio( 328*cda5da8dSAndroid Build Coastguard Worker self._incoming, self._outgoing, 329*cda5da8dSAndroid Build Coastguard Worker server_side=self._server_side, 330*cda5da8dSAndroid Build Coastguard Worker server_hostname=self._server_hostname) 331*cda5da8dSAndroid Build Coastguard Worker 332*cda5da8dSAndroid Build Coastguard Worker # Flow Control 333*cda5da8dSAndroid Build Coastguard Worker 334*cda5da8dSAndroid Build Coastguard Worker self._ssl_writing_paused = False 335*cda5da8dSAndroid Build Coastguard Worker 336*cda5da8dSAndroid Build Coastguard Worker self._app_reading_paused = False 337*cda5da8dSAndroid Build Coastguard Worker 338*cda5da8dSAndroid Build Coastguard Worker self._ssl_reading_paused = False 339*cda5da8dSAndroid Build Coastguard Worker self._incoming_high_water = 0 340*cda5da8dSAndroid Build Coastguard Worker self._incoming_low_water = 0 341*cda5da8dSAndroid Build Coastguard Worker self._set_read_buffer_limits() 342*cda5da8dSAndroid Build Coastguard Worker self._eof_received = False 343*cda5da8dSAndroid Build Coastguard Worker 344*cda5da8dSAndroid Build Coastguard Worker self._app_writing_paused = False 345*cda5da8dSAndroid Build Coastguard Worker self._outgoing_high_water = 0 346*cda5da8dSAndroid Build Coastguard Worker self._outgoing_low_water = 0 347*cda5da8dSAndroid Build Coastguard Worker self._set_write_buffer_limits() 348*cda5da8dSAndroid Build Coastguard Worker self._get_app_transport() 349*cda5da8dSAndroid Build Coastguard Worker 350*cda5da8dSAndroid Build Coastguard Worker def _set_app_protocol(self, app_protocol): 351*cda5da8dSAndroid Build Coastguard Worker self._app_protocol = app_protocol 352*cda5da8dSAndroid Build Coastguard Worker # Make fast hasattr check first 353*cda5da8dSAndroid Build Coastguard Worker if (hasattr(app_protocol, 'get_buffer') and 354*cda5da8dSAndroid Build Coastguard Worker isinstance(app_protocol, protocols.BufferedProtocol)): 355*cda5da8dSAndroid Build Coastguard Worker self._app_protocol_get_buffer = app_protocol.get_buffer 356*cda5da8dSAndroid Build Coastguard Worker self._app_protocol_buffer_updated = app_protocol.buffer_updated 357*cda5da8dSAndroid Build Coastguard Worker self._app_protocol_is_buffer = True 358*cda5da8dSAndroid Build Coastguard Worker else: 359*cda5da8dSAndroid Build Coastguard Worker self._app_protocol_is_buffer = False 360*cda5da8dSAndroid Build Coastguard Worker 361*cda5da8dSAndroid Build Coastguard Worker def _wakeup_waiter(self, exc=None): 362*cda5da8dSAndroid Build Coastguard Worker if self._waiter is None: 363*cda5da8dSAndroid Build Coastguard Worker return 364*cda5da8dSAndroid Build Coastguard Worker if not self._waiter.cancelled(): 365*cda5da8dSAndroid Build Coastguard Worker if exc is not None: 366*cda5da8dSAndroid Build Coastguard Worker self._waiter.set_exception(exc) 367*cda5da8dSAndroid Build Coastguard Worker else: 368*cda5da8dSAndroid Build Coastguard Worker self._waiter.set_result(None) 369*cda5da8dSAndroid Build Coastguard Worker self._waiter = None 370*cda5da8dSAndroid Build Coastguard Worker 371*cda5da8dSAndroid Build Coastguard Worker def _get_app_transport(self): 372*cda5da8dSAndroid Build Coastguard Worker if self._app_transport is None: 373*cda5da8dSAndroid Build Coastguard Worker if self._app_transport_created: 374*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError('Creating _SSLProtocolTransport twice') 375*cda5da8dSAndroid Build Coastguard Worker self._app_transport = _SSLProtocolTransport(self._loop, self) 376*cda5da8dSAndroid Build Coastguard Worker self._app_transport_created = True 377*cda5da8dSAndroid Build Coastguard Worker return self._app_transport 378*cda5da8dSAndroid Build Coastguard Worker 379*cda5da8dSAndroid Build Coastguard Worker def connection_made(self, transport): 380*cda5da8dSAndroid Build Coastguard Worker """Called when the low-level connection is made. 381*cda5da8dSAndroid Build Coastguard Worker 382*cda5da8dSAndroid Build Coastguard Worker Start the SSL handshake. 383*cda5da8dSAndroid Build Coastguard Worker """ 384*cda5da8dSAndroid Build Coastguard Worker self._transport = transport 385*cda5da8dSAndroid Build Coastguard Worker self._start_handshake() 386*cda5da8dSAndroid Build Coastguard Worker 387*cda5da8dSAndroid Build Coastguard Worker def connection_lost(self, exc): 388*cda5da8dSAndroid Build Coastguard Worker """Called when the low-level connection is lost or closed. 389*cda5da8dSAndroid Build Coastguard Worker 390*cda5da8dSAndroid Build Coastguard Worker The argument is an exception object or None (the latter 391*cda5da8dSAndroid Build Coastguard Worker meaning a regular EOF is received or the connection was 392*cda5da8dSAndroid Build Coastguard Worker aborted or closed). 393*cda5da8dSAndroid Build Coastguard Worker """ 394*cda5da8dSAndroid Build Coastguard Worker self._write_backlog.clear() 395*cda5da8dSAndroid Build Coastguard Worker self._outgoing.read() 396*cda5da8dSAndroid Build Coastguard Worker self._conn_lost += 1 397*cda5da8dSAndroid Build Coastguard Worker 398*cda5da8dSAndroid Build Coastguard Worker # Just mark the app transport as closed so that its __dealloc__ 399*cda5da8dSAndroid Build Coastguard Worker # doesn't complain. 400*cda5da8dSAndroid Build Coastguard Worker if self._app_transport is not None: 401*cda5da8dSAndroid Build Coastguard Worker self._app_transport._closed = True 402*cda5da8dSAndroid Build Coastguard Worker 403*cda5da8dSAndroid Build Coastguard Worker if self._state != SSLProtocolState.DO_HANDSHAKE: 404*cda5da8dSAndroid Build Coastguard Worker if ( 405*cda5da8dSAndroid Build Coastguard Worker self._app_state == AppProtocolState.STATE_CON_MADE or 406*cda5da8dSAndroid Build Coastguard Worker self._app_state == AppProtocolState.STATE_EOF 407*cda5da8dSAndroid Build Coastguard Worker ): 408*cda5da8dSAndroid Build Coastguard Worker self._app_state = AppProtocolState.STATE_CON_LOST 409*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._app_protocol.connection_lost, exc) 410*cda5da8dSAndroid Build Coastguard Worker self._set_state(SSLProtocolState.UNWRAPPED) 411*cda5da8dSAndroid Build Coastguard Worker self._transport = None 412*cda5da8dSAndroid Build Coastguard Worker self._app_transport = None 413*cda5da8dSAndroid Build Coastguard Worker self._app_protocol = None 414*cda5da8dSAndroid Build Coastguard Worker self._wakeup_waiter(exc) 415*cda5da8dSAndroid Build Coastguard Worker 416*cda5da8dSAndroid Build Coastguard Worker if self._shutdown_timeout_handle: 417*cda5da8dSAndroid Build Coastguard Worker self._shutdown_timeout_handle.cancel() 418*cda5da8dSAndroid Build Coastguard Worker self._shutdown_timeout_handle = None 419*cda5da8dSAndroid Build Coastguard Worker if self._handshake_timeout_handle: 420*cda5da8dSAndroid Build Coastguard Worker self._handshake_timeout_handle.cancel() 421*cda5da8dSAndroid Build Coastguard Worker self._handshake_timeout_handle = None 422*cda5da8dSAndroid Build Coastguard Worker 423*cda5da8dSAndroid Build Coastguard Worker def get_buffer(self, n): 424*cda5da8dSAndroid Build Coastguard Worker want = n 425*cda5da8dSAndroid Build Coastguard Worker if want <= 0 or want > self.max_size: 426*cda5da8dSAndroid Build Coastguard Worker want = self.max_size 427*cda5da8dSAndroid Build Coastguard Worker if len(self._ssl_buffer) < want: 428*cda5da8dSAndroid Build Coastguard Worker self._ssl_buffer = bytearray(want) 429*cda5da8dSAndroid Build Coastguard Worker self._ssl_buffer_view = memoryview(self._ssl_buffer) 430*cda5da8dSAndroid Build Coastguard Worker return self._ssl_buffer_view 431*cda5da8dSAndroid Build Coastguard Worker 432*cda5da8dSAndroid Build Coastguard Worker def buffer_updated(self, nbytes): 433*cda5da8dSAndroid Build Coastguard Worker self._incoming.write(self._ssl_buffer_view[:nbytes]) 434*cda5da8dSAndroid Build Coastguard Worker 435*cda5da8dSAndroid Build Coastguard Worker if self._state == SSLProtocolState.DO_HANDSHAKE: 436*cda5da8dSAndroid Build Coastguard Worker self._do_handshake() 437*cda5da8dSAndroid Build Coastguard Worker 438*cda5da8dSAndroid Build Coastguard Worker elif self._state == SSLProtocolState.WRAPPED: 439*cda5da8dSAndroid Build Coastguard Worker self._do_read() 440*cda5da8dSAndroid Build Coastguard Worker 441*cda5da8dSAndroid Build Coastguard Worker elif self._state == SSLProtocolState.FLUSHING: 442*cda5da8dSAndroid Build Coastguard Worker self._do_flush() 443*cda5da8dSAndroid Build Coastguard Worker 444*cda5da8dSAndroid Build Coastguard Worker elif self._state == SSLProtocolState.SHUTDOWN: 445*cda5da8dSAndroid Build Coastguard Worker self._do_shutdown() 446*cda5da8dSAndroid Build Coastguard Worker 447*cda5da8dSAndroid Build Coastguard Worker def eof_received(self): 448*cda5da8dSAndroid Build Coastguard Worker """Called when the other end of the low-level stream 449*cda5da8dSAndroid Build Coastguard Worker is half-closed. 450*cda5da8dSAndroid Build Coastguard Worker 451*cda5da8dSAndroid Build Coastguard Worker If this returns a false value (including None), the transport 452*cda5da8dSAndroid Build Coastguard Worker will close itself. If it returns a true value, closing the 453*cda5da8dSAndroid Build Coastguard Worker transport is up to the protocol. 454*cda5da8dSAndroid Build Coastguard Worker """ 455*cda5da8dSAndroid Build Coastguard Worker self._eof_received = True 456*cda5da8dSAndroid Build Coastguard Worker try: 457*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 458*cda5da8dSAndroid Build Coastguard Worker logger.debug("%r received EOF", self) 459*cda5da8dSAndroid Build Coastguard Worker 460*cda5da8dSAndroid Build Coastguard Worker if self._state == SSLProtocolState.DO_HANDSHAKE: 461*cda5da8dSAndroid Build Coastguard Worker self._on_handshake_complete(ConnectionResetError) 462*cda5da8dSAndroid Build Coastguard Worker 463*cda5da8dSAndroid Build Coastguard Worker elif self._state == SSLProtocolState.WRAPPED: 464*cda5da8dSAndroid Build Coastguard Worker self._set_state(SSLProtocolState.FLUSHING) 465*cda5da8dSAndroid Build Coastguard Worker if self._app_reading_paused: 466*cda5da8dSAndroid Build Coastguard Worker return True 467*cda5da8dSAndroid Build Coastguard Worker else: 468*cda5da8dSAndroid Build Coastguard Worker self._do_flush() 469*cda5da8dSAndroid Build Coastguard Worker 470*cda5da8dSAndroid Build Coastguard Worker elif self._state == SSLProtocolState.FLUSHING: 471*cda5da8dSAndroid Build Coastguard Worker self._do_write() 472*cda5da8dSAndroid Build Coastguard Worker self._set_state(SSLProtocolState.SHUTDOWN) 473*cda5da8dSAndroid Build Coastguard Worker self._do_shutdown() 474*cda5da8dSAndroid Build Coastguard Worker 475*cda5da8dSAndroid Build Coastguard Worker elif self._state == SSLProtocolState.SHUTDOWN: 476*cda5da8dSAndroid Build Coastguard Worker self._do_shutdown() 477*cda5da8dSAndroid Build Coastguard Worker 478*cda5da8dSAndroid Build Coastguard Worker except Exception: 479*cda5da8dSAndroid Build Coastguard Worker self._transport.close() 480*cda5da8dSAndroid Build Coastguard Worker raise 481*cda5da8dSAndroid Build Coastguard Worker 482*cda5da8dSAndroid Build Coastguard Worker def _get_extra_info(self, name, default=None): 483*cda5da8dSAndroid Build Coastguard Worker if name in self._extra: 484*cda5da8dSAndroid Build Coastguard Worker return self._extra[name] 485*cda5da8dSAndroid Build Coastguard Worker elif self._transport is not None: 486*cda5da8dSAndroid Build Coastguard Worker return self._transport.get_extra_info(name, default) 487*cda5da8dSAndroid Build Coastguard Worker else: 488*cda5da8dSAndroid Build Coastguard Worker return default 489*cda5da8dSAndroid Build Coastguard Worker 490*cda5da8dSAndroid Build Coastguard Worker def _set_state(self, new_state): 491*cda5da8dSAndroid Build Coastguard Worker allowed = False 492*cda5da8dSAndroid Build Coastguard Worker 493*cda5da8dSAndroid Build Coastguard Worker if new_state == SSLProtocolState.UNWRAPPED: 494*cda5da8dSAndroid Build Coastguard Worker allowed = True 495*cda5da8dSAndroid Build Coastguard Worker 496*cda5da8dSAndroid Build Coastguard Worker elif ( 497*cda5da8dSAndroid Build Coastguard Worker self._state == SSLProtocolState.UNWRAPPED and 498*cda5da8dSAndroid Build Coastguard Worker new_state == SSLProtocolState.DO_HANDSHAKE 499*cda5da8dSAndroid Build Coastguard Worker ): 500*cda5da8dSAndroid Build Coastguard Worker allowed = True 501*cda5da8dSAndroid Build Coastguard Worker 502*cda5da8dSAndroid Build Coastguard Worker elif ( 503*cda5da8dSAndroid Build Coastguard Worker self._state == SSLProtocolState.DO_HANDSHAKE and 504*cda5da8dSAndroid Build Coastguard Worker new_state == SSLProtocolState.WRAPPED 505*cda5da8dSAndroid Build Coastguard Worker ): 506*cda5da8dSAndroid Build Coastguard Worker allowed = True 507*cda5da8dSAndroid Build Coastguard Worker 508*cda5da8dSAndroid Build Coastguard Worker elif ( 509*cda5da8dSAndroid Build Coastguard Worker self._state == SSLProtocolState.WRAPPED and 510*cda5da8dSAndroid Build Coastguard Worker new_state == SSLProtocolState.FLUSHING 511*cda5da8dSAndroid Build Coastguard Worker ): 512*cda5da8dSAndroid Build Coastguard Worker allowed = True 513*cda5da8dSAndroid Build Coastguard Worker 514*cda5da8dSAndroid Build Coastguard Worker elif ( 515*cda5da8dSAndroid Build Coastguard Worker self._state == SSLProtocolState.FLUSHING and 516*cda5da8dSAndroid Build Coastguard Worker new_state == SSLProtocolState.SHUTDOWN 517*cda5da8dSAndroid Build Coastguard Worker ): 518*cda5da8dSAndroid Build Coastguard Worker allowed = True 519*cda5da8dSAndroid Build Coastguard Worker 520*cda5da8dSAndroid Build Coastguard Worker if allowed: 521*cda5da8dSAndroid Build Coastguard Worker self._state = new_state 522*cda5da8dSAndroid Build Coastguard Worker 523*cda5da8dSAndroid Build Coastguard Worker else: 524*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError( 525*cda5da8dSAndroid Build Coastguard Worker 'cannot switch state from {} to {}'.format( 526*cda5da8dSAndroid Build Coastguard Worker self._state, new_state)) 527*cda5da8dSAndroid Build Coastguard Worker 528*cda5da8dSAndroid Build Coastguard Worker # Handshake flow 529*cda5da8dSAndroid Build Coastguard Worker 530*cda5da8dSAndroid Build Coastguard Worker def _start_handshake(self): 531*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 532*cda5da8dSAndroid Build Coastguard Worker logger.debug("%r starts SSL handshake", self) 533*cda5da8dSAndroid Build Coastguard Worker self._handshake_start_time = self._loop.time() 534*cda5da8dSAndroid Build Coastguard Worker else: 535*cda5da8dSAndroid Build Coastguard Worker self._handshake_start_time = None 536*cda5da8dSAndroid Build Coastguard Worker 537*cda5da8dSAndroid Build Coastguard Worker self._set_state(SSLProtocolState.DO_HANDSHAKE) 538*cda5da8dSAndroid Build Coastguard Worker 539*cda5da8dSAndroid Build Coastguard Worker # start handshake timeout count down 540*cda5da8dSAndroid Build Coastguard Worker self._handshake_timeout_handle = \ 541*cda5da8dSAndroid Build Coastguard Worker self._loop.call_later(self._ssl_handshake_timeout, 542*cda5da8dSAndroid Build Coastguard Worker lambda: self._check_handshake_timeout()) 543*cda5da8dSAndroid Build Coastguard Worker 544*cda5da8dSAndroid Build Coastguard Worker self._do_handshake() 545*cda5da8dSAndroid Build Coastguard Worker 546*cda5da8dSAndroid Build Coastguard Worker def _check_handshake_timeout(self): 547*cda5da8dSAndroid Build Coastguard Worker if self._state == SSLProtocolState.DO_HANDSHAKE: 548*cda5da8dSAndroid Build Coastguard Worker msg = ( 549*cda5da8dSAndroid Build Coastguard Worker f"SSL handshake is taking longer than " 550*cda5da8dSAndroid Build Coastguard Worker f"{self._ssl_handshake_timeout} seconds: " 551*cda5da8dSAndroid Build Coastguard Worker f"aborting the connection" 552*cda5da8dSAndroid Build Coastguard Worker ) 553*cda5da8dSAndroid Build Coastguard Worker self._fatal_error(ConnectionAbortedError(msg)) 554*cda5da8dSAndroid Build Coastguard Worker 555*cda5da8dSAndroid Build Coastguard Worker def _do_handshake(self): 556*cda5da8dSAndroid Build Coastguard Worker try: 557*cda5da8dSAndroid Build Coastguard Worker self._sslobj.do_handshake() 558*cda5da8dSAndroid Build Coastguard Worker except SSLAgainErrors: 559*cda5da8dSAndroid Build Coastguard Worker self._process_outgoing() 560*cda5da8dSAndroid Build Coastguard Worker except ssl.SSLError as exc: 561*cda5da8dSAndroid Build Coastguard Worker self._on_handshake_complete(exc) 562*cda5da8dSAndroid Build Coastguard Worker else: 563*cda5da8dSAndroid Build Coastguard Worker self._on_handshake_complete(None) 564*cda5da8dSAndroid Build Coastguard Worker 565*cda5da8dSAndroid Build Coastguard Worker def _on_handshake_complete(self, handshake_exc): 566*cda5da8dSAndroid Build Coastguard Worker if self._handshake_timeout_handle is not None: 567*cda5da8dSAndroid Build Coastguard Worker self._handshake_timeout_handle.cancel() 568*cda5da8dSAndroid Build Coastguard Worker self._handshake_timeout_handle = None 569*cda5da8dSAndroid Build Coastguard Worker 570*cda5da8dSAndroid Build Coastguard Worker sslobj = self._sslobj 571*cda5da8dSAndroid Build Coastguard Worker try: 572*cda5da8dSAndroid Build Coastguard Worker if handshake_exc is None: 573*cda5da8dSAndroid Build Coastguard Worker self._set_state(SSLProtocolState.WRAPPED) 574*cda5da8dSAndroid Build Coastguard Worker else: 575*cda5da8dSAndroid Build Coastguard Worker raise handshake_exc 576*cda5da8dSAndroid Build Coastguard Worker 577*cda5da8dSAndroid Build Coastguard Worker peercert = sslobj.getpeercert() 578*cda5da8dSAndroid Build Coastguard Worker except Exception as exc: 579*cda5da8dSAndroid Build Coastguard Worker self._set_state(SSLProtocolState.UNWRAPPED) 580*cda5da8dSAndroid Build Coastguard Worker if isinstance(exc, ssl.CertificateError): 581*cda5da8dSAndroid Build Coastguard Worker msg = 'SSL handshake failed on verifying the certificate' 582*cda5da8dSAndroid Build Coastguard Worker else: 583*cda5da8dSAndroid Build Coastguard Worker msg = 'SSL handshake failed' 584*cda5da8dSAndroid Build Coastguard Worker self._fatal_error(exc, msg) 585*cda5da8dSAndroid Build Coastguard Worker self._wakeup_waiter(exc) 586*cda5da8dSAndroid Build Coastguard Worker return 587*cda5da8dSAndroid Build Coastguard Worker 588*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 589*cda5da8dSAndroid Build Coastguard Worker dt = self._loop.time() - self._handshake_start_time 590*cda5da8dSAndroid Build Coastguard Worker logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3) 591*cda5da8dSAndroid Build Coastguard Worker 592*cda5da8dSAndroid Build Coastguard Worker # Add extra info that becomes available after handshake. 593*cda5da8dSAndroid Build Coastguard Worker self._extra.update(peercert=peercert, 594*cda5da8dSAndroid Build Coastguard Worker cipher=sslobj.cipher(), 595*cda5da8dSAndroid Build Coastguard Worker compression=sslobj.compression(), 596*cda5da8dSAndroid Build Coastguard Worker ssl_object=sslobj) 597*cda5da8dSAndroid Build Coastguard Worker if self._app_state == AppProtocolState.STATE_INIT: 598*cda5da8dSAndroid Build Coastguard Worker self._app_state = AppProtocolState.STATE_CON_MADE 599*cda5da8dSAndroid Build Coastguard Worker self._app_protocol.connection_made(self._get_app_transport()) 600*cda5da8dSAndroid Build Coastguard Worker self._wakeup_waiter() 601*cda5da8dSAndroid Build Coastguard Worker self._do_read() 602*cda5da8dSAndroid Build Coastguard Worker 603*cda5da8dSAndroid Build Coastguard Worker # Shutdown flow 604*cda5da8dSAndroid Build Coastguard Worker 605*cda5da8dSAndroid Build Coastguard Worker def _start_shutdown(self): 606*cda5da8dSAndroid Build Coastguard Worker if ( 607*cda5da8dSAndroid Build Coastguard Worker self._state in ( 608*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.FLUSHING, 609*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.SHUTDOWN, 610*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.UNWRAPPED 611*cda5da8dSAndroid Build Coastguard Worker ) 612*cda5da8dSAndroid Build Coastguard Worker ): 613*cda5da8dSAndroid Build Coastguard Worker return 614*cda5da8dSAndroid Build Coastguard Worker if self._app_transport is not None: 615*cda5da8dSAndroid Build Coastguard Worker self._app_transport._closed = True 616*cda5da8dSAndroid Build Coastguard Worker if self._state == SSLProtocolState.DO_HANDSHAKE: 617*cda5da8dSAndroid Build Coastguard Worker self._abort() 618*cda5da8dSAndroid Build Coastguard Worker else: 619*cda5da8dSAndroid Build Coastguard Worker self._set_state(SSLProtocolState.FLUSHING) 620*cda5da8dSAndroid Build Coastguard Worker self._shutdown_timeout_handle = self._loop.call_later( 621*cda5da8dSAndroid Build Coastguard Worker self._ssl_shutdown_timeout, 622*cda5da8dSAndroid Build Coastguard Worker lambda: self._check_shutdown_timeout() 623*cda5da8dSAndroid Build Coastguard Worker ) 624*cda5da8dSAndroid Build Coastguard Worker self._do_flush() 625*cda5da8dSAndroid Build Coastguard Worker 626*cda5da8dSAndroid Build Coastguard Worker def _check_shutdown_timeout(self): 627*cda5da8dSAndroid Build Coastguard Worker if ( 628*cda5da8dSAndroid Build Coastguard Worker self._state in ( 629*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.FLUSHING, 630*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.SHUTDOWN 631*cda5da8dSAndroid Build Coastguard Worker ) 632*cda5da8dSAndroid Build Coastguard Worker ): 633*cda5da8dSAndroid Build Coastguard Worker self._transport._force_close( 634*cda5da8dSAndroid Build Coastguard Worker exceptions.TimeoutError('SSL shutdown timed out')) 635*cda5da8dSAndroid Build Coastguard Worker 636*cda5da8dSAndroid Build Coastguard Worker def _do_flush(self): 637*cda5da8dSAndroid Build Coastguard Worker self._do_read() 638*cda5da8dSAndroid Build Coastguard Worker self._set_state(SSLProtocolState.SHUTDOWN) 639*cda5da8dSAndroid Build Coastguard Worker self._do_shutdown() 640*cda5da8dSAndroid Build Coastguard Worker 641*cda5da8dSAndroid Build Coastguard Worker def _do_shutdown(self): 642*cda5da8dSAndroid Build Coastguard Worker try: 643*cda5da8dSAndroid Build Coastguard Worker if not self._eof_received: 644*cda5da8dSAndroid Build Coastguard Worker self._sslobj.unwrap() 645*cda5da8dSAndroid Build Coastguard Worker except SSLAgainErrors: 646*cda5da8dSAndroid Build Coastguard Worker self._process_outgoing() 647*cda5da8dSAndroid Build Coastguard Worker except ssl.SSLError as exc: 648*cda5da8dSAndroid Build Coastguard Worker self._on_shutdown_complete(exc) 649*cda5da8dSAndroid Build Coastguard Worker else: 650*cda5da8dSAndroid Build Coastguard Worker self._process_outgoing() 651*cda5da8dSAndroid Build Coastguard Worker self._call_eof_received() 652*cda5da8dSAndroid Build Coastguard Worker self._on_shutdown_complete(None) 653*cda5da8dSAndroid Build Coastguard Worker 654*cda5da8dSAndroid Build Coastguard Worker def _on_shutdown_complete(self, shutdown_exc): 655*cda5da8dSAndroid Build Coastguard Worker if self._shutdown_timeout_handle is not None: 656*cda5da8dSAndroid Build Coastguard Worker self._shutdown_timeout_handle.cancel() 657*cda5da8dSAndroid Build Coastguard Worker self._shutdown_timeout_handle = None 658*cda5da8dSAndroid Build Coastguard Worker 659*cda5da8dSAndroid Build Coastguard Worker if shutdown_exc: 660*cda5da8dSAndroid Build Coastguard Worker self._fatal_error(shutdown_exc) 661*cda5da8dSAndroid Build Coastguard Worker else: 662*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._transport.close) 663*cda5da8dSAndroid Build Coastguard Worker 664*cda5da8dSAndroid Build Coastguard Worker def _abort(self): 665*cda5da8dSAndroid Build Coastguard Worker self._set_state(SSLProtocolState.UNWRAPPED) 666*cda5da8dSAndroid Build Coastguard Worker if self._transport is not None: 667*cda5da8dSAndroid Build Coastguard Worker self._transport.abort() 668*cda5da8dSAndroid Build Coastguard Worker 669*cda5da8dSAndroid Build Coastguard Worker # Outgoing flow 670*cda5da8dSAndroid Build Coastguard Worker 671*cda5da8dSAndroid Build Coastguard Worker def _write_appdata(self, list_of_data): 672*cda5da8dSAndroid Build Coastguard Worker if ( 673*cda5da8dSAndroid Build Coastguard Worker self._state in ( 674*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.FLUSHING, 675*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.SHUTDOWN, 676*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.UNWRAPPED 677*cda5da8dSAndroid Build Coastguard Worker ) 678*cda5da8dSAndroid Build Coastguard Worker ): 679*cda5da8dSAndroid Build Coastguard Worker if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES: 680*cda5da8dSAndroid Build Coastguard Worker logger.warning('SSL connection is closed') 681*cda5da8dSAndroid Build Coastguard Worker self._conn_lost += 1 682*cda5da8dSAndroid Build Coastguard Worker return 683*cda5da8dSAndroid Build Coastguard Worker 684*cda5da8dSAndroid Build Coastguard Worker for data in list_of_data: 685*cda5da8dSAndroid Build Coastguard Worker self._write_backlog.append(data) 686*cda5da8dSAndroid Build Coastguard Worker self._write_buffer_size += len(data) 687*cda5da8dSAndroid Build Coastguard Worker 688*cda5da8dSAndroid Build Coastguard Worker try: 689*cda5da8dSAndroid Build Coastguard Worker if self._state == SSLProtocolState.WRAPPED: 690*cda5da8dSAndroid Build Coastguard Worker self._do_write() 691*cda5da8dSAndroid Build Coastguard Worker 692*cda5da8dSAndroid Build Coastguard Worker except Exception as ex: 693*cda5da8dSAndroid Build Coastguard Worker self._fatal_error(ex, 'Fatal error on SSL protocol') 694*cda5da8dSAndroid Build Coastguard Worker 695*cda5da8dSAndroid Build Coastguard Worker def _do_write(self): 696*cda5da8dSAndroid Build Coastguard Worker try: 697*cda5da8dSAndroid Build Coastguard Worker while self._write_backlog: 698*cda5da8dSAndroid Build Coastguard Worker data = self._write_backlog[0] 699*cda5da8dSAndroid Build Coastguard Worker count = self._sslobj.write(data) 700*cda5da8dSAndroid Build Coastguard Worker data_len = len(data) 701*cda5da8dSAndroid Build Coastguard Worker if count < data_len: 702*cda5da8dSAndroid Build Coastguard Worker self._write_backlog[0] = data[count:] 703*cda5da8dSAndroid Build Coastguard Worker self._write_buffer_size -= count 704*cda5da8dSAndroid Build Coastguard Worker else: 705*cda5da8dSAndroid Build Coastguard Worker del self._write_backlog[0] 706*cda5da8dSAndroid Build Coastguard Worker self._write_buffer_size -= data_len 707*cda5da8dSAndroid Build Coastguard Worker except SSLAgainErrors: 708*cda5da8dSAndroid Build Coastguard Worker pass 709*cda5da8dSAndroid Build Coastguard Worker self._process_outgoing() 710*cda5da8dSAndroid Build Coastguard Worker 711*cda5da8dSAndroid Build Coastguard Worker def _process_outgoing(self): 712*cda5da8dSAndroid Build Coastguard Worker if not self._ssl_writing_paused: 713*cda5da8dSAndroid Build Coastguard Worker data = self._outgoing.read() 714*cda5da8dSAndroid Build Coastguard Worker if len(data): 715*cda5da8dSAndroid Build Coastguard Worker self._transport.write(data) 716*cda5da8dSAndroid Build Coastguard Worker self._control_app_writing() 717*cda5da8dSAndroid Build Coastguard Worker 718*cda5da8dSAndroid Build Coastguard Worker # Incoming flow 719*cda5da8dSAndroid Build Coastguard Worker 720*cda5da8dSAndroid Build Coastguard Worker def _do_read(self): 721*cda5da8dSAndroid Build Coastguard Worker if ( 722*cda5da8dSAndroid Build Coastguard Worker self._state not in ( 723*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.WRAPPED, 724*cda5da8dSAndroid Build Coastguard Worker SSLProtocolState.FLUSHING, 725*cda5da8dSAndroid Build Coastguard Worker ) 726*cda5da8dSAndroid Build Coastguard Worker ): 727*cda5da8dSAndroid Build Coastguard Worker return 728*cda5da8dSAndroid Build Coastguard Worker try: 729*cda5da8dSAndroid Build Coastguard Worker if not self._app_reading_paused: 730*cda5da8dSAndroid Build Coastguard Worker if self._app_protocol_is_buffer: 731*cda5da8dSAndroid Build Coastguard Worker self._do_read__buffered() 732*cda5da8dSAndroid Build Coastguard Worker else: 733*cda5da8dSAndroid Build Coastguard Worker self._do_read__copied() 734*cda5da8dSAndroid Build Coastguard Worker if self._write_backlog: 735*cda5da8dSAndroid Build Coastguard Worker self._do_write() 736*cda5da8dSAndroid Build Coastguard Worker else: 737*cda5da8dSAndroid Build Coastguard Worker self._process_outgoing() 738*cda5da8dSAndroid Build Coastguard Worker self._control_ssl_reading() 739*cda5da8dSAndroid Build Coastguard Worker except Exception as ex: 740*cda5da8dSAndroid Build Coastguard Worker self._fatal_error(ex, 'Fatal error on SSL protocol') 741*cda5da8dSAndroid Build Coastguard Worker 742*cda5da8dSAndroid Build Coastguard Worker def _do_read__buffered(self): 743*cda5da8dSAndroid Build Coastguard Worker offset = 0 744*cda5da8dSAndroid Build Coastguard Worker count = 1 745*cda5da8dSAndroid Build Coastguard Worker 746*cda5da8dSAndroid Build Coastguard Worker buf = self._app_protocol_get_buffer(self._get_read_buffer_size()) 747*cda5da8dSAndroid Build Coastguard Worker wants = len(buf) 748*cda5da8dSAndroid Build Coastguard Worker 749*cda5da8dSAndroid Build Coastguard Worker try: 750*cda5da8dSAndroid Build Coastguard Worker count = self._sslobj.read(wants, buf) 751*cda5da8dSAndroid Build Coastguard Worker 752*cda5da8dSAndroid Build Coastguard Worker if count > 0: 753*cda5da8dSAndroid Build Coastguard Worker offset = count 754*cda5da8dSAndroid Build Coastguard Worker while offset < wants: 755*cda5da8dSAndroid Build Coastguard Worker count = self._sslobj.read(wants - offset, buf[offset:]) 756*cda5da8dSAndroid Build Coastguard Worker if count > 0: 757*cda5da8dSAndroid Build Coastguard Worker offset += count 758*cda5da8dSAndroid Build Coastguard Worker else: 759*cda5da8dSAndroid Build Coastguard Worker break 760*cda5da8dSAndroid Build Coastguard Worker else: 761*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(lambda: self._do_read()) 762*cda5da8dSAndroid Build Coastguard Worker except SSLAgainErrors: 763*cda5da8dSAndroid Build Coastguard Worker pass 764*cda5da8dSAndroid Build Coastguard Worker if offset > 0: 765*cda5da8dSAndroid Build Coastguard Worker self._app_protocol_buffer_updated(offset) 766*cda5da8dSAndroid Build Coastguard Worker if not count: 767*cda5da8dSAndroid Build Coastguard Worker # close_notify 768*cda5da8dSAndroid Build Coastguard Worker self._call_eof_received() 769*cda5da8dSAndroid Build Coastguard Worker self._start_shutdown() 770*cda5da8dSAndroid Build Coastguard Worker 771*cda5da8dSAndroid Build Coastguard Worker def _do_read__copied(self): 772*cda5da8dSAndroid Build Coastguard Worker chunk = b'1' 773*cda5da8dSAndroid Build Coastguard Worker zero = True 774*cda5da8dSAndroid Build Coastguard Worker one = False 775*cda5da8dSAndroid Build Coastguard Worker 776*cda5da8dSAndroid Build Coastguard Worker try: 777*cda5da8dSAndroid Build Coastguard Worker while True: 778*cda5da8dSAndroid Build Coastguard Worker chunk = self._sslobj.read(self.max_size) 779*cda5da8dSAndroid Build Coastguard Worker if not chunk: 780*cda5da8dSAndroid Build Coastguard Worker break 781*cda5da8dSAndroid Build Coastguard Worker if zero: 782*cda5da8dSAndroid Build Coastguard Worker zero = False 783*cda5da8dSAndroid Build Coastguard Worker one = True 784*cda5da8dSAndroid Build Coastguard Worker first = chunk 785*cda5da8dSAndroid Build Coastguard Worker elif one: 786*cda5da8dSAndroid Build Coastguard Worker one = False 787*cda5da8dSAndroid Build Coastguard Worker data = [first, chunk] 788*cda5da8dSAndroid Build Coastguard Worker else: 789*cda5da8dSAndroid Build Coastguard Worker data.append(chunk) 790*cda5da8dSAndroid Build Coastguard Worker except SSLAgainErrors: 791*cda5da8dSAndroid Build Coastguard Worker pass 792*cda5da8dSAndroid Build Coastguard Worker if one: 793*cda5da8dSAndroid Build Coastguard Worker self._app_protocol.data_received(first) 794*cda5da8dSAndroid Build Coastguard Worker elif not zero: 795*cda5da8dSAndroid Build Coastguard Worker self._app_protocol.data_received(b''.join(data)) 796*cda5da8dSAndroid Build Coastguard Worker if not chunk: 797*cda5da8dSAndroid Build Coastguard Worker # close_notify 798*cda5da8dSAndroid Build Coastguard Worker self._call_eof_received() 799*cda5da8dSAndroid Build Coastguard Worker self._start_shutdown() 800*cda5da8dSAndroid Build Coastguard Worker 801*cda5da8dSAndroid Build Coastguard Worker def _call_eof_received(self): 802*cda5da8dSAndroid Build Coastguard Worker try: 803*cda5da8dSAndroid Build Coastguard Worker if self._app_state == AppProtocolState.STATE_CON_MADE: 804*cda5da8dSAndroid Build Coastguard Worker self._app_state = AppProtocolState.STATE_EOF 805*cda5da8dSAndroid Build Coastguard Worker keep_open = self._app_protocol.eof_received() 806*cda5da8dSAndroid Build Coastguard Worker if keep_open: 807*cda5da8dSAndroid Build Coastguard Worker logger.warning('returning true from eof_received() ' 808*cda5da8dSAndroid Build Coastguard Worker 'has no effect when using ssl') 809*cda5da8dSAndroid Build Coastguard Worker except (KeyboardInterrupt, SystemExit): 810*cda5da8dSAndroid Build Coastguard Worker raise 811*cda5da8dSAndroid Build Coastguard Worker except BaseException as ex: 812*cda5da8dSAndroid Build Coastguard Worker self._fatal_error(ex, 'Error calling eof_received()') 813*cda5da8dSAndroid Build Coastguard Worker 814*cda5da8dSAndroid Build Coastguard Worker # Flow control for writes from APP socket 815*cda5da8dSAndroid Build Coastguard Worker 816*cda5da8dSAndroid Build Coastguard Worker def _control_app_writing(self): 817*cda5da8dSAndroid Build Coastguard Worker size = self._get_write_buffer_size() 818*cda5da8dSAndroid Build Coastguard Worker if size >= self._outgoing_high_water and not self._app_writing_paused: 819*cda5da8dSAndroid Build Coastguard Worker self._app_writing_paused = True 820*cda5da8dSAndroid Build Coastguard Worker try: 821*cda5da8dSAndroid Build Coastguard Worker self._app_protocol.pause_writing() 822*cda5da8dSAndroid Build Coastguard Worker except (KeyboardInterrupt, SystemExit): 823*cda5da8dSAndroid Build Coastguard Worker raise 824*cda5da8dSAndroid Build Coastguard Worker except BaseException as exc: 825*cda5da8dSAndroid Build Coastguard Worker self._loop.call_exception_handler({ 826*cda5da8dSAndroid Build Coastguard Worker 'message': 'protocol.pause_writing() failed', 827*cda5da8dSAndroid Build Coastguard Worker 'exception': exc, 828*cda5da8dSAndroid Build Coastguard Worker 'transport': self._app_transport, 829*cda5da8dSAndroid Build Coastguard Worker 'protocol': self, 830*cda5da8dSAndroid Build Coastguard Worker }) 831*cda5da8dSAndroid Build Coastguard Worker elif size <= self._outgoing_low_water and self._app_writing_paused: 832*cda5da8dSAndroid Build Coastguard Worker self._app_writing_paused = False 833*cda5da8dSAndroid Build Coastguard Worker try: 834*cda5da8dSAndroid Build Coastguard Worker self._app_protocol.resume_writing() 835*cda5da8dSAndroid Build Coastguard Worker except (KeyboardInterrupt, SystemExit): 836*cda5da8dSAndroid Build Coastguard Worker raise 837*cda5da8dSAndroid Build Coastguard Worker except BaseException as exc: 838*cda5da8dSAndroid Build Coastguard Worker self._loop.call_exception_handler({ 839*cda5da8dSAndroid Build Coastguard Worker 'message': 'protocol.resume_writing() failed', 840*cda5da8dSAndroid Build Coastguard Worker 'exception': exc, 841*cda5da8dSAndroid Build Coastguard Worker 'transport': self._app_transport, 842*cda5da8dSAndroid Build Coastguard Worker 'protocol': self, 843*cda5da8dSAndroid Build Coastguard Worker }) 844*cda5da8dSAndroid Build Coastguard Worker 845*cda5da8dSAndroid Build Coastguard Worker def _get_write_buffer_size(self): 846*cda5da8dSAndroid Build Coastguard Worker return self._outgoing.pending + self._write_buffer_size 847*cda5da8dSAndroid Build Coastguard Worker 848*cda5da8dSAndroid Build Coastguard Worker def _set_write_buffer_limits(self, high=None, low=None): 849*cda5da8dSAndroid Build Coastguard Worker high, low = add_flowcontrol_defaults( 850*cda5da8dSAndroid Build Coastguard Worker high, low, constants.FLOW_CONTROL_HIGH_WATER_SSL_WRITE) 851*cda5da8dSAndroid Build Coastguard Worker self._outgoing_high_water = high 852*cda5da8dSAndroid Build Coastguard Worker self._outgoing_low_water = low 853*cda5da8dSAndroid Build Coastguard Worker 854*cda5da8dSAndroid Build Coastguard Worker # Flow control for reads to APP socket 855*cda5da8dSAndroid Build Coastguard Worker 856*cda5da8dSAndroid Build Coastguard Worker def _pause_reading(self): 857*cda5da8dSAndroid Build Coastguard Worker self._app_reading_paused = True 858*cda5da8dSAndroid Build Coastguard Worker 859*cda5da8dSAndroid Build Coastguard Worker def _resume_reading(self): 860*cda5da8dSAndroid Build Coastguard Worker if self._app_reading_paused: 861*cda5da8dSAndroid Build Coastguard Worker self._app_reading_paused = False 862*cda5da8dSAndroid Build Coastguard Worker 863*cda5da8dSAndroid Build Coastguard Worker def resume(): 864*cda5da8dSAndroid Build Coastguard Worker if self._state == SSLProtocolState.WRAPPED: 865*cda5da8dSAndroid Build Coastguard Worker self._do_read() 866*cda5da8dSAndroid Build Coastguard Worker elif self._state == SSLProtocolState.FLUSHING: 867*cda5da8dSAndroid Build Coastguard Worker self._do_flush() 868*cda5da8dSAndroid Build Coastguard Worker elif self._state == SSLProtocolState.SHUTDOWN: 869*cda5da8dSAndroid Build Coastguard Worker self._do_shutdown() 870*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(resume) 871*cda5da8dSAndroid Build Coastguard Worker 872*cda5da8dSAndroid Build Coastguard Worker # Flow control for reads from SSL socket 873*cda5da8dSAndroid Build Coastguard Worker 874*cda5da8dSAndroid Build Coastguard Worker def _control_ssl_reading(self): 875*cda5da8dSAndroid Build Coastguard Worker size = self._get_read_buffer_size() 876*cda5da8dSAndroid Build Coastguard Worker if size >= self._incoming_high_water and not self._ssl_reading_paused: 877*cda5da8dSAndroid Build Coastguard Worker self._ssl_reading_paused = True 878*cda5da8dSAndroid Build Coastguard Worker self._transport.pause_reading() 879*cda5da8dSAndroid Build Coastguard Worker elif size <= self._incoming_low_water and self._ssl_reading_paused: 880*cda5da8dSAndroid Build Coastguard Worker self._ssl_reading_paused = False 881*cda5da8dSAndroid Build Coastguard Worker self._transport.resume_reading() 882*cda5da8dSAndroid Build Coastguard Worker 883*cda5da8dSAndroid Build Coastguard Worker def _set_read_buffer_limits(self, high=None, low=None): 884*cda5da8dSAndroid Build Coastguard Worker high, low = add_flowcontrol_defaults( 885*cda5da8dSAndroid Build Coastguard Worker high, low, constants.FLOW_CONTROL_HIGH_WATER_SSL_READ) 886*cda5da8dSAndroid Build Coastguard Worker self._incoming_high_water = high 887*cda5da8dSAndroid Build Coastguard Worker self._incoming_low_water = low 888*cda5da8dSAndroid Build Coastguard Worker 889*cda5da8dSAndroid Build Coastguard Worker def _get_read_buffer_size(self): 890*cda5da8dSAndroid Build Coastguard Worker return self._incoming.pending 891*cda5da8dSAndroid Build Coastguard Worker 892*cda5da8dSAndroid Build Coastguard Worker # Flow control for writes to SSL socket 893*cda5da8dSAndroid Build Coastguard Worker 894*cda5da8dSAndroid Build Coastguard Worker def pause_writing(self): 895*cda5da8dSAndroid Build Coastguard Worker """Called when the low-level transport's buffer goes over 896*cda5da8dSAndroid Build Coastguard Worker the high-water mark. 897*cda5da8dSAndroid Build Coastguard Worker """ 898*cda5da8dSAndroid Build Coastguard Worker assert not self._ssl_writing_paused 899*cda5da8dSAndroid Build Coastguard Worker self._ssl_writing_paused = True 900*cda5da8dSAndroid Build Coastguard Worker 901*cda5da8dSAndroid Build Coastguard Worker def resume_writing(self): 902*cda5da8dSAndroid Build Coastguard Worker """Called when the low-level transport's buffer drains below 903*cda5da8dSAndroid Build Coastguard Worker the low-water mark. 904*cda5da8dSAndroid Build Coastguard Worker """ 905*cda5da8dSAndroid Build Coastguard Worker assert self._ssl_writing_paused 906*cda5da8dSAndroid Build Coastguard Worker self._ssl_writing_paused = False 907*cda5da8dSAndroid Build Coastguard Worker self._process_outgoing() 908*cda5da8dSAndroid Build Coastguard Worker 909*cda5da8dSAndroid Build Coastguard Worker def _fatal_error(self, exc, message='Fatal error on transport'): 910*cda5da8dSAndroid Build Coastguard Worker if self._transport: 911*cda5da8dSAndroid Build Coastguard Worker self._transport._force_close(exc) 912*cda5da8dSAndroid Build Coastguard Worker 913*cda5da8dSAndroid Build Coastguard Worker if isinstance(exc, OSError): 914*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 915*cda5da8dSAndroid Build Coastguard Worker logger.debug("%r: %s", self, message, exc_info=True) 916*cda5da8dSAndroid Build Coastguard Worker elif not isinstance(exc, exceptions.CancelledError): 917*cda5da8dSAndroid Build Coastguard Worker self._loop.call_exception_handler({ 918*cda5da8dSAndroid Build Coastguard Worker 'message': message, 919*cda5da8dSAndroid Build Coastguard Worker 'exception': exc, 920*cda5da8dSAndroid Build Coastguard Worker 'transport': self._transport, 921*cda5da8dSAndroid Build Coastguard Worker 'protocol': self, 922*cda5da8dSAndroid Build Coastguard Worker }) 923