blob: 0c8f01ad8f1a8e95dfcf07633ff03df82fcfa8e7 [file] [log] [blame]
Victor Stinner231b4042015-01-14 00:19:09 +01001import collections
Victor Stinner978a9af2015-01-29 17:50:58 +01002import warnings
Victor Stinner231b4042015-01-14 00:19:09 +01003try:
4 import ssl
5except ImportError: # pragma: no cover
6 ssl = None
7
Yury Selivanov77bc04a2016-06-28 10:55:36 -04008from . import base_events
Victor Stinner231b4042015-01-14 00:19:09 +01009from . import protocols
10from . import transports
11from .log import logger
12
13
14def _create_transport_context(server_side, server_hostname):
15 if server_side:
16 raise ValueError('Server side SSL needs a valid SSLContext')
17
18 # Client side may pass ssl=True to use a default
19 # context; in that case the sslcontext passed is None.
20 # The default is secure for client connections.
Andrew Svetlov51d546a2017-11-18 18:54:05 +020021 # Python 3.4+: use up-to-date strong settings.
22 sslcontext = ssl.create_default_context()
23 if not server_hostname:
24 sslcontext.check_hostname = False
Victor Stinner231b4042015-01-14 00:19:09 +010025 return sslcontext
26
27
Victor Stinner231b4042015-01-14 00:19:09 +010028# States of an _SSLPipe.
29_UNWRAPPED = "UNWRAPPED"
30_DO_HANDSHAKE = "DO_HANDSHAKE"
31_WRAPPED = "WRAPPED"
32_SHUTDOWN = "SHUTDOWN"
33
34
35class _SSLPipe(object):
36 """An SSL "Pipe".
37
38 An SSL pipe allows you to communicate with an SSL/TLS protocol instance
39 through memory buffers. It can be used to implement a security layer for an
40 existing connection where you don't have access to the connection's file
41 descriptor, or for some reason you don't want to use it.
42
43 An SSL pipe can be in "wrapped" and "unwrapped" mode. In unwrapped mode,
44 data is passed through untransformed. In wrapped mode, application level
45 data is encrypted to SSL record level data and vice versa. The SSL record
46 level is the lowest level in the SSL protocol suite and is what travels
47 as-is over the wire.
48
49 An SslPipe initially is in "unwrapped" mode. To start SSL, call
50 do_handshake(). To shutdown SSL again, call unwrap().
51 """
52
53 max_size = 256 * 1024 # Buffer size passed to read()
54
55 def __init__(self, context, server_side, server_hostname=None):
56 """
57 The *context* argument specifies the ssl.SSLContext to use.
58
59 The *server_side* argument indicates whether this is a server side or
60 client side transport.
61
62 The optional *server_hostname* argument can be used to specify the
63 hostname you are connecting to. You may only specify this parameter if
64 the _ssl module supports Server Name Indication (SNI).
65 """
66 self._context = context
67 self._server_side = server_side
68 self._server_hostname = server_hostname
69 self._state = _UNWRAPPED
70 self._incoming = ssl.MemoryBIO()
71 self._outgoing = ssl.MemoryBIO()
72 self._sslobj = None
73 self._need_ssldata = False
74 self._handshake_cb = None
75 self._shutdown_cb = None
76
77 @property
78 def context(self):
79 """The SSL context passed to the constructor."""
80 return self._context
81
82 @property
83 def ssl_object(self):
84 """The internal ssl.SSLObject instance.
85
86 Return None if the pipe is not wrapped.
87 """
88 return self._sslobj
89
90 @property
91 def need_ssldata(self):
92 """Whether more record level data is needed to complete a handshake
93 that is currently in progress."""
94 return self._need_ssldata
95
96 @property
97 def wrapped(self):
98 """
99 Whether a security layer is currently in effect.
100
101 Return False during handshake.
102 """
103 return self._state == _WRAPPED
104
105 def do_handshake(self, callback=None):
106 """Start the SSL handshake.
107
108 Return a list of ssldata. A ssldata element is a list of buffers
109
110 The optional *callback* argument can be used to install a callback that
111 will be called when the handshake is complete. The callback will be
112 called with None if successful, else an exception instance.
113 """
114 if self._state != _UNWRAPPED:
115 raise RuntimeError('handshake in progress or completed')
116 self._sslobj = self._context.wrap_bio(
117 self._incoming, self._outgoing,
118 server_side=self._server_side,
119 server_hostname=self._server_hostname)
120 self._state = _DO_HANDSHAKE
121 self._handshake_cb = callback
122 ssldata, appdata = self.feed_ssldata(b'', only_handshake=True)
123 assert len(appdata) == 0
124 return ssldata
125
126 def shutdown(self, callback=None):
127 """Start the SSL shutdown sequence.
128
129 Return a list of ssldata. A ssldata element is a list of buffers
130
131 The optional *callback* argument can be used to install a callback that
132 will be called when the shutdown is complete. The callback will be
133 called without arguments.
134 """
135 if self._state == _UNWRAPPED:
136 raise RuntimeError('no security layer present')
137 if self._state == _SHUTDOWN:
138 raise RuntimeError('shutdown in progress')
139 assert self._state in (_WRAPPED, _DO_HANDSHAKE)
140 self._state = _SHUTDOWN
141 self._shutdown_cb = callback
142 ssldata, appdata = self.feed_ssldata(b'')
143 assert appdata == [] or appdata == [b'']
144 return ssldata
145
146 def feed_eof(self):
147 """Send a potentially "ragged" EOF.
148
149 This method will raise an SSL_ERROR_EOF exception if the EOF is
150 unexpected.
151 """
152 self._incoming.write_eof()
153 ssldata, appdata = self.feed_ssldata(b'')
154 assert appdata == [] or appdata == [b'']
155
156 def feed_ssldata(self, data, only_handshake=False):
157 """Feed SSL record level data into the pipe.
158
159 The data must be a bytes instance. It is OK to send an empty bytes
160 instance. This can be used to get ssldata for a handshake initiated by
161 this endpoint.
162
163 Return a (ssldata, appdata) tuple. The ssldata element is a list of
164 buffers containing SSL data that needs to be sent to the remote SSL.
165
166 The appdata element is a list of buffers containing plaintext data that
167 needs to be forwarded to the application. The appdata list may contain
168 an empty buffer indicating an SSL "close_notify" alert. This alert must
169 be acknowledged by calling shutdown().
170 """
171 if self._state == _UNWRAPPED:
172 # If unwrapped, pass plaintext data straight through.
173 if data:
174 appdata = [data]
175 else:
176 appdata = []
177 return ([], appdata)
178
179 self._need_ssldata = False
180 if data:
181 self._incoming.write(data)
182
183 ssldata = []
184 appdata = []
185 try:
186 if self._state == _DO_HANDSHAKE:
187 # Call do_handshake() until it doesn't raise anymore.
188 self._sslobj.do_handshake()
189 self._state = _WRAPPED
190 if self._handshake_cb:
191 self._handshake_cb(None)
192 if only_handshake:
193 return (ssldata, appdata)
194 # Handshake done: execute the wrapped block
195
196 if self._state == _WRAPPED:
197 # Main state: read data from SSL until close_notify
198 while True:
199 chunk = self._sslobj.read(self.max_size)
200 appdata.append(chunk)
201 if not chunk: # close_notify
202 break
203
204 elif self._state == _SHUTDOWN:
205 # Call shutdown() until it doesn't raise anymore.
206 self._sslobj.unwrap()
207 self._sslobj = None
208 self._state = _UNWRAPPED
209 if self._shutdown_cb:
210 self._shutdown_cb()
211
212 elif self._state == _UNWRAPPED:
213 # Drain possible plaintext data after close_notify.
214 appdata.append(self._incoming.read())
215 except (ssl.SSLError, ssl.CertificateError) as exc:
216 if getattr(exc, 'errno', None) not in (
217 ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE,
218 ssl.SSL_ERROR_SYSCALL):
219 if self._state == _DO_HANDSHAKE and self._handshake_cb:
220 self._handshake_cb(exc)
221 raise
222 self._need_ssldata = (exc.errno == ssl.SSL_ERROR_WANT_READ)
223
224 # Check for record level data that needs to be sent back.
225 # Happens for the initial handshake and renegotiations.
226 if self._outgoing.pending:
227 ssldata.append(self._outgoing.read())
228 return (ssldata, appdata)
229
230 def feed_appdata(self, data, offset=0):
231 """Feed plaintext data into the pipe.
232
233 Return an (ssldata, offset) tuple. The ssldata element is a list of
234 buffers containing record level data that needs to be sent to the
235 remote SSL instance. The offset is the number of plaintext bytes that
236 were processed, which may be less than the length of data.
237
238 NOTE: In case of short writes, this call MUST be retried with the SAME
239 buffer passed into the *data* argument (i.e. the id() must be the
240 same). This is an OpenSSL requirement. A further particularity is that
241 a short write will always have offset == 0, because the _ssl module
242 does not enable partial writes. And even though the offset is zero,
243 there will still be encrypted data in ssldata.
244 """
245 assert 0 <= offset <= len(data)
246 if self._state == _UNWRAPPED:
247 # pass through data in unwrapped mode
248 if offset < len(data):
249 ssldata = [data[offset:]]
250 else:
251 ssldata = []
252 return (ssldata, len(data))
253
254 ssldata = []
255 view = memoryview(data)
256 while True:
257 self._need_ssldata = False
258 try:
259 if offset < len(view):
260 offset += self._sslobj.write(view[offset:])
261 except ssl.SSLError as exc:
262 # It is not allowed to call write() after unwrap() until the
263 # close_notify is acknowledged. We return the condition to the
264 # caller as a short write.
265 if exc.reason == 'PROTOCOL_IS_SHUTDOWN':
266 exc.errno = ssl.SSL_ERROR_WANT_READ
267 if exc.errno not in (ssl.SSL_ERROR_WANT_READ,
268 ssl.SSL_ERROR_WANT_WRITE,
269 ssl.SSL_ERROR_SYSCALL):
270 raise
271 self._need_ssldata = (exc.errno == ssl.SSL_ERROR_WANT_READ)
272
273 # See if there's any record level data back for us.
274 if self._outgoing.pending:
275 ssldata.append(self._outgoing.read())
276 if offset == len(view) or self._need_ssldata:
277 break
278 return (ssldata, offset)
279
280
281class _SSLProtocolTransport(transports._FlowControlMixin,
282 transports.Transport):
283
jlacolineea2ef5d2017-10-19 19:49:57 +0200284 def __init__(self, loop, ssl_protocol):
Victor Stinner231b4042015-01-14 00:19:09 +0100285 self._loop = loop
Victor Stinnerf7dc7fb2015-09-21 18:06:17 +0200286 # SSLProtocol instance
Victor Stinner231b4042015-01-14 00:19:09 +0100287 self._ssl_protocol = ssl_protocol
Victor Stinner978a9af2015-01-29 17:50:58 +0100288 self._closed = False
Victor Stinner231b4042015-01-14 00:19:09 +0100289
290 def get_extra_info(self, name, default=None):
291 """Get optional transport information."""
292 return self._ssl_protocol._get_extra_info(name, default)
293
Yury Selivanova05a6ef2016-09-11 21:11:02 -0400294 def set_protocol(self, protocol):
jlacolineea2ef5d2017-10-19 19:49:57 +0200295 self._ssl_protocol._app_protocol = protocol
Yury Selivanova05a6ef2016-09-11 21:11:02 -0400296
297 def get_protocol(self):
jlacolineea2ef5d2017-10-19 19:49:57 +0200298 return self._ssl_protocol._app_protocol
Yury Selivanova05a6ef2016-09-11 21:11:02 -0400299
Yury Selivanov5bb1afb2015-11-16 12:43:21 -0500300 def is_closing(self):
301 return self._closed
302
Victor Stinner231b4042015-01-14 00:19:09 +0100303 def close(self):
304 """Close the transport.
305
306 Buffered data will be flushed asynchronously. No more data
307 will be received. After all buffered data is flushed, the
308 protocol's connection_lost() method will (eventually) called
309 with None as its argument.
310 """
Victor Stinner978a9af2015-01-29 17:50:58 +0100311 self._closed = True
Victor Stinner231b4042015-01-14 00:19:09 +0100312 self._ssl_protocol._start_shutdown()
313
INADA Naoki3e2ad8e2017-04-25 10:57:18 +0900314 def __del__(self):
315 if not self._closed:
Yury Selivanov6370f342017-12-10 18:36:12 -0500316 warnings.warn(f"unclosed transport {self!r}", ResourceWarning,
INADA Naoki3e2ad8e2017-04-25 10:57:18 +0900317 source=self)
318 self.close()
Victor Stinner978a9af2015-01-29 17:50:58 +0100319
Victor Stinner231b4042015-01-14 00:19:09 +0100320 def pause_reading(self):
321 """Pause the receiving end.
322
323 No data will be passed to the protocol's data_received()
324 method until resume_reading() is called.
325 """
326 self._ssl_protocol._transport.pause_reading()
327
328 def resume_reading(self):
329 """Resume the receiving end.
330
331 Data received will once again be passed to the protocol's
332 data_received() method.
333 """
334 self._ssl_protocol._transport.resume_reading()
335
336 def set_write_buffer_limits(self, high=None, low=None):
337 """Set the high- and low-water limits for write flow control.
338
339 These two values control when to call the protocol's
340 pause_writing() and resume_writing() methods. If specified,
341 the low-water limit must be less than or equal to the
342 high-water limit. Neither value can be negative.
343
344 The defaults are implementation-specific. If only the
Serhiy Storchakad65c9492015-11-02 14:10:23 +0200345 high-water limit is given, the low-water limit defaults to an
Victor Stinner231b4042015-01-14 00:19:09 +0100346 implementation-specific value less than or equal to the
347 high-water limit. Setting high to zero forces low to zero as
348 well, and causes pause_writing() to be called whenever the
349 buffer becomes non-empty. Setting low to zero causes
350 resume_writing() to be called only once the buffer is empty.
351 Use of zero for either limit is generally sub-optimal as it
352 reduces opportunities for doing I/O and computation
353 concurrently.
354 """
355 self._ssl_protocol._transport.set_write_buffer_limits(high, low)
356
357 def get_write_buffer_size(self):
358 """Return the current size of the write buffer."""
359 return self._ssl_protocol._transport.get_write_buffer_size()
360
361 def write(self, data):
362 """Write some data bytes to the transport.
363
364 This does not block; it buffers the data and arranges for it
365 to be sent out asynchronously.
366 """
367 if not isinstance(data, (bytes, bytearray, memoryview)):
Yury Selivanov6370f342017-12-10 18:36:12 -0500368 raise TypeError(f"data: expecting a bytes-like instance, "
369 f"got {type(data).__name__}")
Victor Stinner231b4042015-01-14 00:19:09 +0100370 if not data:
371 return
372 self._ssl_protocol._write_appdata(data)
373
374 def can_write_eof(self):
375 """Return True if this transport supports write_eof(), False if not."""
376 return False
377
378 def abort(self):
379 """Close the transport immediately.
380
381 Buffered data will be lost. No more data will be received.
382 The protocol's connection_lost() method will (eventually) be
383 called with None as its argument.
384 """
385 self._ssl_protocol._abort()
386
387
388class SSLProtocol(protocols.Protocol):
389 """SSL protocol.
390
391 Implementation of SSL on top of a socket using incoming and outgoing
392 buffers which are ssl.MemoryBIO objects.
393 """
394
395 def __init__(self, loop, app_protocol, sslcontext, waiter,
Yury Selivanov92e7c7f2016-10-05 19:39:54 -0400396 server_side=False, server_hostname=None,
Yury Selivanov09663de2017-06-11 16:46:35 +0200397 call_connection_made=True):
Victor Stinner231b4042015-01-14 00:19:09 +0100398 if ssl is None:
399 raise RuntimeError('stdlib ssl module not available')
400
401 if not sslcontext:
Yury Selivanov6370f342017-12-10 18:36:12 -0500402 sslcontext = _create_transport_context(
403 server_side, server_hostname)
Victor Stinner231b4042015-01-14 00:19:09 +0100404
405 self._server_side = server_side
406 if server_hostname and not server_side:
407 self._server_hostname = server_hostname
408 else:
409 self._server_hostname = None
410 self._sslcontext = sslcontext
411 # SSL-specific extra info. More info are set when the handshake
412 # completes.
413 self._extra = dict(sslcontext=sslcontext)
414
415 # App data write buffering
416 self._write_backlog = collections.deque()
417 self._write_buffer_size = 0
418
419 self._waiter = waiter
Victor Stinner231b4042015-01-14 00:19:09 +0100420 self._loop = loop
421 self._app_protocol = app_protocol
jlacolineea2ef5d2017-10-19 19:49:57 +0200422 self._app_transport = _SSLProtocolTransport(self._loop, self)
Victor Stinnerf7dc7fb2015-09-21 18:06:17 +0200423 # _SSLPipe instance (None until the connection is made)
Victor Stinner231b4042015-01-14 00:19:09 +0100424 self._sslpipe = None
425 self._session_established = False
426 self._in_handshake = False
427 self._in_shutdown = False
Victor Stinnerf7dc7fb2015-09-21 18:06:17 +0200428 # transport, ex: SelectorSocketTransport
Victor Stinner7e222f42015-01-15 13:16:27 +0100429 self._transport = None
Yury Selivanov92e7c7f2016-10-05 19:39:54 -0400430 self._call_connection_made = call_connection_made
Victor Stinner231b4042015-01-14 00:19:09 +0100431
Victor Stinnerf07801b2015-01-29 00:36:35 +0100432 def _wakeup_waiter(self, exc=None):
433 if self._waiter is None:
434 return
435 if not self._waiter.cancelled():
436 if exc is not None:
437 self._waiter.set_exception(exc)
438 else:
439 self._waiter.set_result(None)
440 self._waiter = None
441
Victor Stinner231b4042015-01-14 00:19:09 +0100442 def connection_made(self, transport):
443 """Called when the low-level connection is made.
444
445 Start the SSL handshake.
446 """
447 self._transport = transport
448 self._sslpipe = _SSLPipe(self._sslcontext,
449 self._server_side,
450 self._server_hostname)
451 self._start_handshake()
452
453 def connection_lost(self, exc):
454 """Called when the low-level connection is lost or closed.
455
456 The argument is an exception object or None (the latter
457 meaning a regular EOF is received or the connection was
458 aborted or closed).
459 """
460 if self._session_established:
461 self._session_established = False
462 self._loop.call_soon(self._app_protocol.connection_lost, exc)
463 self._transport = None
464 self._app_transport = None
Yury Selivanovb1461aa2016-12-16 11:50:41 -0500465 self._wakeup_waiter(exc)
Victor Stinner231b4042015-01-14 00:19:09 +0100466
467 def pause_writing(self):
468 """Called when the low-level transport's buffer goes over
469 the high-water mark.
470 """
471 self._app_protocol.pause_writing()
472
473 def resume_writing(self):
474 """Called when the low-level transport's buffer drains below
475 the low-water mark.
476 """
477 self._app_protocol.resume_writing()
478
479 def data_received(self, data):
480 """Called when some SSL data is received.
481
482 The argument is a bytes object.
483 """
484 try:
485 ssldata, appdata = self._sslpipe.feed_ssldata(data)
486 except ssl.SSLError as e:
487 if self._loop.get_debug():
488 logger.warning('%r: SSL error %s (reason %s)',
489 self, e.errno, e.reason)
490 self._abort()
491 return
492
493 for chunk in ssldata:
494 self._transport.write(chunk)
495
496 for chunk in appdata:
497 if chunk:
498 self._app_protocol.data_received(chunk)
499 else:
500 self._start_shutdown()
501 break
502
503 def eof_received(self):
504 """Called when the other end of the low-level stream
505 is half-closed.
506
507 If this returns a false value (including None), the transport
508 will close itself. If it returns a true value, closing the
509 transport is up to the protocol.
510 """
511 try:
512 if self._loop.get_debug():
513 logger.debug("%r received EOF", self)
Victor Stinnerb507cba2015-01-29 00:35:56 +0100514
Victor Stinnerf07801b2015-01-29 00:36:35 +0100515 self._wakeup_waiter(ConnectionResetError)
Victor Stinnerb507cba2015-01-29 00:35:56 +0100516
Victor Stinner231b4042015-01-14 00:19:09 +0100517 if not self._in_handshake:
518 keep_open = self._app_protocol.eof_received()
519 if keep_open:
520 logger.warning('returning true from eof_received() '
521 'has no effect when using ssl')
522 finally:
523 self._transport.close()
524
525 def _get_extra_info(self, name, default=None):
526 if name in self._extra:
527 return self._extra[name]
Nikolay Kim2b27e2e2017-03-12 12:23:30 -0700528 elif self._transport is not None:
Victor Stinner231b4042015-01-14 00:19:09 +0100529 return self._transport.get_extra_info(name, default)
Nikolay Kim2b27e2e2017-03-12 12:23:30 -0700530 else:
531 return default
Victor Stinner231b4042015-01-14 00:19:09 +0100532
533 def _start_shutdown(self):
534 if self._in_shutdown:
535 return
Nikolay Kima0e3d2d2017-06-09 14:46:14 -0700536 if self._in_handshake:
537 self._abort()
538 else:
539 self._in_shutdown = True
540 self._write_appdata(b'')
Victor Stinner231b4042015-01-14 00:19:09 +0100541
542 def _write_appdata(self, data):
543 self._write_backlog.append((data, 0))
544 self._write_buffer_size += len(data)
545 self._process_write_backlog()
546
547 def _start_handshake(self):
548 if self._loop.get_debug():
549 logger.debug("%r starts SSL handshake", self)
550 self._handshake_start_time = self._loop.time()
551 else:
552 self._handshake_start_time = None
553 self._in_handshake = True
554 # (b'', 1) is a special value in _process_write_backlog() to do
555 # the SSL handshake
556 self._write_backlog.append((b'', 1))
557 self._loop.call_soon(self._process_write_backlog)
558
559 def _on_handshake_complete(self, handshake_exc):
560 self._in_handshake = False
561
562 sslobj = self._sslpipe.ssl_object
Victor Stinner231b4042015-01-14 00:19:09 +0100563 try:
564 if handshake_exc is not None:
565 raise handshake_exc
Victor Stinner177e9f02015-01-14 16:56:20 +0100566
567 peercert = sslobj.getpeercert()
Victor Stinner231b4042015-01-14 00:19:09 +0100568 if not hasattr(self._sslcontext, 'check_hostname'):
569 # Verify hostname if requested, Python 3.4+ uses check_hostname
570 # and checks the hostname in do_handshake()
Yury Selivanov6370f342017-12-10 18:36:12 -0500571 if (self._server_hostname and
572 self._sslcontext.verify_mode != ssl.CERT_NONE):
Victor Stinner231b4042015-01-14 00:19:09 +0100573 ssl.match_hostname(peercert, self._server_hostname)
574 except BaseException as exc:
575 if self._loop.get_debug():
576 if isinstance(exc, ssl.CertificateError):
577 logger.warning("%r: SSL handshake failed "
578 "on verifying the certificate",
579 self, exc_info=True)
580 else:
581 logger.warning("%r: SSL handshake failed",
582 self, exc_info=True)
583 self._transport.close()
584 if isinstance(exc, Exception):
Victor Stinnerf07801b2015-01-29 00:36:35 +0100585 self._wakeup_waiter(exc)
Victor Stinner231b4042015-01-14 00:19:09 +0100586 return
587 else:
588 raise
589
590 if self._loop.get_debug():
591 dt = self._loop.time() - self._handshake_start_time
592 logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3)
593
594 # Add extra info that becomes available after handshake.
595 self._extra.update(peercert=peercert,
596 cipher=sslobj.cipher(),
597 compression=sslobj.compression(),
Victor Stinnerf7dc7fb2015-09-21 18:06:17 +0200598 ssl_object=sslobj,
Victor Stinner231b4042015-01-14 00:19:09 +0100599 )
Yury Selivanov92e7c7f2016-10-05 19:39:54 -0400600 if self._call_connection_made:
601 self._app_protocol.connection_made(self._app_transport)
Victor Stinnerf07801b2015-01-29 00:36:35 +0100602 self._wakeup_waiter()
Victor Stinner231b4042015-01-14 00:19:09 +0100603 self._session_established = True
Victor Stinner042dad72015-01-15 09:41:48 +0100604 # In case transport.write() was already called. Don't call
Martin Panter46f50722016-05-26 05:35:26 +0000605 # immediately _process_write_backlog(), but schedule it:
Victor Stinner042dad72015-01-15 09:41:48 +0100606 # _on_handshake_complete() can be called indirectly from
607 # _process_write_backlog(), and _process_write_backlog() is not
608 # reentrant.
Victor Stinner72bdefb2015-01-15 09:44:13 +0100609 self._loop.call_soon(self._process_write_backlog)
Victor Stinner231b4042015-01-14 00:19:09 +0100610
611 def _process_write_backlog(self):
612 # Try to make progress on the write backlog.
613 if self._transport is None:
614 return
615
616 try:
617 for i in range(len(self._write_backlog)):
618 data, offset = self._write_backlog[0]
619 if data:
620 ssldata, offset = self._sslpipe.feed_appdata(data, offset)
621 elif offset:
Yury Selivanov8c125eb2015-08-05 14:06:23 -0400622 ssldata = self._sslpipe.do_handshake(
623 self._on_handshake_complete)
Victor Stinner231b4042015-01-14 00:19:09 +0100624 offset = 1
625 else:
626 ssldata = self._sslpipe.shutdown(self._finalize)
627 offset = 1
628
629 for chunk in ssldata:
630 self._transport.write(chunk)
631
632 if offset < len(data):
633 self._write_backlog[0] = (data, offset)
634 # A short write means that a write is blocked on a read
635 # We need to enable reading if it is paused!
636 assert self._sslpipe.need_ssldata
637 if self._transport._paused:
638 self._transport.resume_reading()
639 break
640
641 # An entire chunk from the backlog was processed. We can
642 # delete it and reduce the outstanding buffer size.
643 del self._write_backlog[0]
644 self._write_buffer_size -= len(data)
645 except BaseException as exc:
646 if self._in_handshake:
Yury Selivanov8c125eb2015-08-05 14:06:23 -0400647 # BaseExceptions will be re-raised in _on_handshake_complete.
Victor Stinner231b4042015-01-14 00:19:09 +0100648 self._on_handshake_complete(exc)
649 else:
650 self._fatal_error(exc, 'Fatal error on SSL transport')
Yury Selivanov8c125eb2015-08-05 14:06:23 -0400651 if not isinstance(exc, Exception):
652 # BaseException
653 raise
Victor Stinner231b4042015-01-14 00:19:09 +0100654
655 def _fatal_error(self, exc, message='Fatal error on transport'):
656 # Should be called from exception handler only.
Victor Stinnerc94a93a2016-04-01 21:43:39 +0200657 if isinstance(exc, base_events._FATAL_ERROR_IGNORE):
Victor Stinner231b4042015-01-14 00:19:09 +0100658 if self._loop.get_debug():
659 logger.debug("%r: %s", self, message, exc_info=True)
660 else:
661 self._loop.call_exception_handler({
662 'message': message,
663 'exception': exc,
664 'transport': self._transport,
665 'protocol': self,
666 })
667 if self._transport:
668 self._transport._force_close(exc)
669
670 def _finalize(self):
Michaël Sghaïerd1f57512017-06-09 18:29:46 -0400671 self._sslpipe = None
672
Victor Stinner231b4042015-01-14 00:19:09 +0100673 if self._transport is not None:
674 self._transport.close()
675
676 def _abort(self):
Michaël Sghaïerd1f57512017-06-09 18:29:46 -0400677 try:
678 if self._transport is not None:
Victor Stinner231b4042015-01-14 00:19:09 +0100679 self._transport.abort()
Michaël Sghaïerd1f57512017-06-09 18:29:46 -0400680 finally:
681 self._finalize()