blob: 8da8570d66d4fb67913f2cff18fff839507beb26 [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
Yury Selivanovd757aaf2017-12-18 17:03:23 -0500320 def is_reading(self):
321 tr = self._ssl_protocol._transport
322 if tr is None:
323 raise RuntimeError('SSL transport has not been initialized yet')
324 return tr.is_reading()
325
Victor Stinner231b4042015-01-14 00:19:09 +0100326 def pause_reading(self):
327 """Pause the receiving end.
328
329 No data will be passed to the protocol's data_received()
330 method until resume_reading() is called.
331 """
332 self._ssl_protocol._transport.pause_reading()
333
334 def resume_reading(self):
335 """Resume the receiving end.
336
337 Data received will once again be passed to the protocol's
338 data_received() method.
339 """
340 self._ssl_protocol._transport.resume_reading()
341
342 def set_write_buffer_limits(self, high=None, low=None):
343 """Set the high- and low-water limits for write flow control.
344
345 These two values control when to call the protocol's
346 pause_writing() and resume_writing() methods. If specified,
347 the low-water limit must be less than or equal to the
348 high-water limit. Neither value can be negative.
349
350 The defaults are implementation-specific. If only the
Serhiy Storchakad65c9492015-11-02 14:10:23 +0200351 high-water limit is given, the low-water limit defaults to an
Victor Stinner231b4042015-01-14 00:19:09 +0100352 implementation-specific value less than or equal to the
353 high-water limit. Setting high to zero forces low to zero as
354 well, and causes pause_writing() to be called whenever the
355 buffer becomes non-empty. Setting low to zero causes
356 resume_writing() to be called only once the buffer is empty.
357 Use of zero for either limit is generally sub-optimal as it
358 reduces opportunities for doing I/O and computation
359 concurrently.
360 """
361 self._ssl_protocol._transport.set_write_buffer_limits(high, low)
362
363 def get_write_buffer_size(self):
364 """Return the current size of the write buffer."""
365 return self._ssl_protocol._transport.get_write_buffer_size()
366
367 def write(self, data):
368 """Write some data bytes to the transport.
369
370 This does not block; it buffers the data and arranges for it
371 to be sent out asynchronously.
372 """
373 if not isinstance(data, (bytes, bytearray, memoryview)):
Yury Selivanov6370f342017-12-10 18:36:12 -0500374 raise TypeError(f"data: expecting a bytes-like instance, "
375 f"got {type(data).__name__}")
Victor Stinner231b4042015-01-14 00:19:09 +0100376 if not data:
377 return
378 self._ssl_protocol._write_appdata(data)
379
380 def can_write_eof(self):
381 """Return True if this transport supports write_eof(), False if not."""
382 return False
383
384 def abort(self):
385 """Close the transport immediately.
386
387 Buffered data will be lost. No more data will be received.
388 The protocol's connection_lost() method will (eventually) be
389 called with None as its argument.
390 """
391 self._ssl_protocol._abort()
392
393
394class SSLProtocol(protocols.Protocol):
395 """SSL protocol.
396
397 Implementation of SSL on top of a socket using incoming and outgoing
398 buffers which are ssl.MemoryBIO objects.
399 """
400
401 def __init__(self, loop, app_protocol, sslcontext, waiter,
Yury Selivanov92e7c7f2016-10-05 19:39:54 -0400402 server_side=False, server_hostname=None,
Yury Selivanov09663de2017-06-11 16:46:35 +0200403 call_connection_made=True):
Victor Stinner231b4042015-01-14 00:19:09 +0100404 if ssl is None:
405 raise RuntimeError('stdlib ssl module not available')
406
407 if not sslcontext:
Yury Selivanov6370f342017-12-10 18:36:12 -0500408 sslcontext = _create_transport_context(
409 server_side, server_hostname)
Victor Stinner231b4042015-01-14 00:19:09 +0100410
411 self._server_side = server_side
412 if server_hostname and not server_side:
413 self._server_hostname = server_hostname
414 else:
415 self._server_hostname = None
416 self._sslcontext = sslcontext
417 # SSL-specific extra info. More info are set when the handshake
418 # completes.
419 self._extra = dict(sslcontext=sslcontext)
420
421 # App data write buffering
422 self._write_backlog = collections.deque()
423 self._write_buffer_size = 0
424
425 self._waiter = waiter
Victor Stinner231b4042015-01-14 00:19:09 +0100426 self._loop = loop
427 self._app_protocol = app_protocol
jlacolineea2ef5d2017-10-19 19:49:57 +0200428 self._app_transport = _SSLProtocolTransport(self._loop, self)
Victor Stinnerf7dc7fb2015-09-21 18:06:17 +0200429 # _SSLPipe instance (None until the connection is made)
Victor Stinner231b4042015-01-14 00:19:09 +0100430 self._sslpipe = None
431 self._session_established = False
432 self._in_handshake = False
433 self._in_shutdown = False
Victor Stinnerf7dc7fb2015-09-21 18:06:17 +0200434 # transport, ex: SelectorSocketTransport
Victor Stinner7e222f42015-01-15 13:16:27 +0100435 self._transport = None
Yury Selivanov92e7c7f2016-10-05 19:39:54 -0400436 self._call_connection_made = call_connection_made
Victor Stinner231b4042015-01-14 00:19:09 +0100437
Victor Stinnerf07801b2015-01-29 00:36:35 +0100438 def _wakeup_waiter(self, exc=None):
439 if self._waiter is None:
440 return
441 if not self._waiter.cancelled():
442 if exc is not None:
443 self._waiter.set_exception(exc)
444 else:
445 self._waiter.set_result(None)
446 self._waiter = None
447
Victor Stinner231b4042015-01-14 00:19:09 +0100448 def connection_made(self, transport):
449 """Called when the low-level connection is made.
450
451 Start the SSL handshake.
452 """
453 self._transport = transport
454 self._sslpipe = _SSLPipe(self._sslcontext,
455 self._server_side,
456 self._server_hostname)
457 self._start_handshake()
458
459 def connection_lost(self, exc):
460 """Called when the low-level connection is lost or closed.
461
462 The argument is an exception object or None (the latter
463 meaning a regular EOF is received or the connection was
464 aborted or closed).
465 """
466 if self._session_established:
467 self._session_established = False
468 self._loop.call_soon(self._app_protocol.connection_lost, exc)
469 self._transport = None
470 self._app_transport = None
Yury Selivanovb1461aa2016-12-16 11:50:41 -0500471 self._wakeup_waiter(exc)
Victor Stinner231b4042015-01-14 00:19:09 +0100472
473 def pause_writing(self):
474 """Called when the low-level transport's buffer goes over
475 the high-water mark.
476 """
477 self._app_protocol.pause_writing()
478
479 def resume_writing(self):
480 """Called when the low-level transport's buffer drains below
481 the low-water mark.
482 """
483 self._app_protocol.resume_writing()
484
485 def data_received(self, data):
486 """Called when some SSL data is received.
487
488 The argument is a bytes object.
489 """
490 try:
491 ssldata, appdata = self._sslpipe.feed_ssldata(data)
492 except ssl.SSLError as e:
493 if self._loop.get_debug():
494 logger.warning('%r: SSL error %s (reason %s)',
495 self, e.errno, e.reason)
496 self._abort()
497 return
498
499 for chunk in ssldata:
500 self._transport.write(chunk)
501
502 for chunk in appdata:
503 if chunk:
504 self._app_protocol.data_received(chunk)
505 else:
506 self._start_shutdown()
507 break
508
509 def eof_received(self):
510 """Called when the other end of the low-level stream
511 is half-closed.
512
513 If this returns a false value (including None), the transport
514 will close itself. If it returns a true value, closing the
515 transport is up to the protocol.
516 """
517 try:
518 if self._loop.get_debug():
519 logger.debug("%r received EOF", self)
Victor Stinnerb507cba2015-01-29 00:35:56 +0100520
Victor Stinnerf07801b2015-01-29 00:36:35 +0100521 self._wakeup_waiter(ConnectionResetError)
Victor Stinnerb507cba2015-01-29 00:35:56 +0100522
Victor Stinner231b4042015-01-14 00:19:09 +0100523 if not self._in_handshake:
524 keep_open = self._app_protocol.eof_received()
525 if keep_open:
526 logger.warning('returning true from eof_received() '
527 'has no effect when using ssl')
528 finally:
529 self._transport.close()
530
531 def _get_extra_info(self, name, default=None):
532 if name in self._extra:
533 return self._extra[name]
Nikolay Kim2b27e2e2017-03-12 12:23:30 -0700534 elif self._transport is not None:
Victor Stinner231b4042015-01-14 00:19:09 +0100535 return self._transport.get_extra_info(name, default)
Nikolay Kim2b27e2e2017-03-12 12:23:30 -0700536 else:
537 return default
Victor Stinner231b4042015-01-14 00:19:09 +0100538
539 def _start_shutdown(self):
540 if self._in_shutdown:
541 return
Nikolay Kima0e3d2d2017-06-09 14:46:14 -0700542 if self._in_handshake:
543 self._abort()
544 else:
545 self._in_shutdown = True
546 self._write_appdata(b'')
Victor Stinner231b4042015-01-14 00:19:09 +0100547
548 def _write_appdata(self, data):
549 self._write_backlog.append((data, 0))
550 self._write_buffer_size += len(data)
551 self._process_write_backlog()
552
553 def _start_handshake(self):
554 if self._loop.get_debug():
555 logger.debug("%r starts SSL handshake", self)
556 self._handshake_start_time = self._loop.time()
557 else:
558 self._handshake_start_time = None
559 self._in_handshake = True
560 # (b'', 1) is a special value in _process_write_backlog() to do
561 # the SSL handshake
562 self._write_backlog.append((b'', 1))
563 self._loop.call_soon(self._process_write_backlog)
564
565 def _on_handshake_complete(self, handshake_exc):
566 self._in_handshake = False
567
568 sslobj = self._sslpipe.ssl_object
Victor Stinner231b4042015-01-14 00:19:09 +0100569 try:
570 if handshake_exc is not None:
571 raise handshake_exc
Victor Stinner177e9f02015-01-14 16:56:20 +0100572
573 peercert = sslobj.getpeercert()
Victor Stinner231b4042015-01-14 00:19:09 +0100574 if not hasattr(self._sslcontext, 'check_hostname'):
575 # Verify hostname if requested, Python 3.4+ uses check_hostname
576 # and checks the hostname in do_handshake()
Yury Selivanov6370f342017-12-10 18:36:12 -0500577 if (self._server_hostname and
578 self._sslcontext.verify_mode != ssl.CERT_NONE):
Victor Stinner231b4042015-01-14 00:19:09 +0100579 ssl.match_hostname(peercert, self._server_hostname)
580 except BaseException as exc:
581 if self._loop.get_debug():
582 if isinstance(exc, ssl.CertificateError):
583 logger.warning("%r: SSL handshake failed "
584 "on verifying the certificate",
585 self, exc_info=True)
586 else:
587 logger.warning("%r: SSL handshake failed",
588 self, exc_info=True)
589 self._transport.close()
590 if isinstance(exc, Exception):
Victor Stinnerf07801b2015-01-29 00:36:35 +0100591 self._wakeup_waiter(exc)
Victor Stinner231b4042015-01-14 00:19:09 +0100592 return
593 else:
594 raise
595
596 if self._loop.get_debug():
597 dt = self._loop.time() - self._handshake_start_time
598 logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3)
599
600 # Add extra info that becomes available after handshake.
601 self._extra.update(peercert=peercert,
602 cipher=sslobj.cipher(),
603 compression=sslobj.compression(),
Victor Stinnerf7dc7fb2015-09-21 18:06:17 +0200604 ssl_object=sslobj,
Victor Stinner231b4042015-01-14 00:19:09 +0100605 )
Yury Selivanov92e7c7f2016-10-05 19:39:54 -0400606 if self._call_connection_made:
607 self._app_protocol.connection_made(self._app_transport)
Victor Stinnerf07801b2015-01-29 00:36:35 +0100608 self._wakeup_waiter()
Victor Stinner231b4042015-01-14 00:19:09 +0100609 self._session_established = True
Victor Stinner042dad72015-01-15 09:41:48 +0100610 # In case transport.write() was already called. Don't call
Martin Panter46f50722016-05-26 05:35:26 +0000611 # immediately _process_write_backlog(), but schedule it:
Victor Stinner042dad72015-01-15 09:41:48 +0100612 # _on_handshake_complete() can be called indirectly from
613 # _process_write_backlog(), and _process_write_backlog() is not
614 # reentrant.
Victor Stinner72bdefb2015-01-15 09:44:13 +0100615 self._loop.call_soon(self._process_write_backlog)
Victor Stinner231b4042015-01-14 00:19:09 +0100616
617 def _process_write_backlog(self):
618 # Try to make progress on the write backlog.
619 if self._transport is None:
620 return
621
622 try:
623 for i in range(len(self._write_backlog)):
624 data, offset = self._write_backlog[0]
625 if data:
626 ssldata, offset = self._sslpipe.feed_appdata(data, offset)
627 elif offset:
Yury Selivanov8c125eb2015-08-05 14:06:23 -0400628 ssldata = self._sslpipe.do_handshake(
629 self._on_handshake_complete)
Victor Stinner231b4042015-01-14 00:19:09 +0100630 offset = 1
631 else:
632 ssldata = self._sslpipe.shutdown(self._finalize)
633 offset = 1
634
635 for chunk in ssldata:
636 self._transport.write(chunk)
637
638 if offset < len(data):
639 self._write_backlog[0] = (data, offset)
640 # A short write means that a write is blocked on a read
641 # We need to enable reading if it is paused!
642 assert self._sslpipe.need_ssldata
643 if self._transport._paused:
644 self._transport.resume_reading()
645 break
646
647 # An entire chunk from the backlog was processed. We can
648 # delete it and reduce the outstanding buffer size.
649 del self._write_backlog[0]
650 self._write_buffer_size -= len(data)
651 except BaseException as exc:
652 if self._in_handshake:
Yury Selivanov8c125eb2015-08-05 14:06:23 -0400653 # BaseExceptions will be re-raised in _on_handshake_complete.
Victor Stinner231b4042015-01-14 00:19:09 +0100654 self._on_handshake_complete(exc)
655 else:
656 self._fatal_error(exc, 'Fatal error on SSL transport')
Yury Selivanov8c125eb2015-08-05 14:06:23 -0400657 if not isinstance(exc, Exception):
658 # BaseException
659 raise
Victor Stinner231b4042015-01-14 00:19:09 +0100660
661 def _fatal_error(self, exc, message='Fatal error on transport'):
662 # Should be called from exception handler only.
Victor Stinnerc94a93a2016-04-01 21:43:39 +0200663 if isinstance(exc, base_events._FATAL_ERROR_IGNORE):
Victor Stinner231b4042015-01-14 00:19:09 +0100664 if self._loop.get_debug():
665 logger.debug("%r: %s", self, message, exc_info=True)
666 else:
667 self._loop.call_exception_handler({
668 'message': message,
669 'exception': exc,
670 'transport': self._transport,
671 'protocol': self,
672 })
673 if self._transport:
674 self._transport._force_close(exc)
675
676 def _finalize(self):
Michaël Sghaïerd1f57512017-06-09 18:29:46 -0400677 self._sslpipe = None
678
Victor Stinner231b4042015-01-14 00:19:09 +0100679 if self._transport is not None:
680 self._transport.close()
681
682 def _abort(self):
Michaël Sghaïerd1f57512017-06-09 18:29:46 -0400683 try:
684 if self._transport is not None:
Victor Stinner231b4042015-01-14 00:19:09 +0100685 self._transport.abort()
Michaël Sghaïerd1f57512017-06-09 18:29:46 -0400686 finally:
687 self._finalize()