A utility class to write to and read from a non-blocking SSL socket. If the socket passed to the constructor is already connected, it should be wrapped with:: ssl.wrap_socket(sock, do_handshake_on_connect=False, **kwargs) before constructing the `SSLIOStream`. Unconnected soc
| 1339 | |
| 1340 | |
| 1341 | class SSLIOStream(IOStream): |
| 1342 | """A utility class to write to and read from a non-blocking SSL socket. |
| 1343 | |
| 1344 | If the socket passed to the constructor is already connected, |
| 1345 | it should be wrapped with:: |
| 1346 | |
| 1347 | ssl.wrap_socket(sock, do_handshake_on_connect=False, **kwargs) |
| 1348 | |
| 1349 | before constructing the `SSLIOStream`. Unconnected sockets will be |
| 1350 | wrapped when `IOStream.connect` is finished. |
| 1351 | """ |
| 1352 | |
| 1353 | socket = None # type: ssl.SSLSocket |
| 1354 | |
| 1355 | def __init__(self, *args: Any, **kwargs: Any) -> None: |
| 1356 | """The ``ssl_options`` keyword argument may either be an |
| 1357 | `ssl.SSLContext` object or a dictionary of keywords arguments |
| 1358 | for `ssl.wrap_socket` |
| 1359 | """ |
| 1360 | self._ssl_options = kwargs.pop("ssl_options", _client_ssl_defaults) |
| 1361 | super().__init__(*args, **kwargs) |
| 1362 | self._ssl_accepting = True |
| 1363 | self._handshake_reading = False |
| 1364 | self._handshake_writing = False |
| 1365 | self._server_hostname = None # type: Optional[str] |
| 1366 | |
| 1367 | # If the socket is already connected, attempt to start the handshake. |
| 1368 | try: |
| 1369 | self.socket.getpeername() |
| 1370 | except socket.error: |
| 1371 | pass |
| 1372 | else: |
| 1373 | # Indirectly start the handshake, which will run on the next |
| 1374 | # IOLoop iteration and then the real IO state will be set in |
| 1375 | # _handle_events. |
| 1376 | self._add_io_state(self.io_loop.WRITE) |
| 1377 | |
| 1378 | def reading(self) -> bool: |
| 1379 | return self._handshake_reading or super().reading() |
| 1380 | |
| 1381 | def writing(self) -> bool: |
| 1382 | return self._handshake_writing or super().writing() |
| 1383 | |
| 1384 | def _do_ssl_handshake(self) -> None: |
| 1385 | # Based on code from test_ssl.py in the python stdlib |
| 1386 | try: |
| 1387 | self._handshake_reading = False |
| 1388 | self._handshake_writing = False |
| 1389 | self.socket.do_handshake() |
| 1390 | except ssl.SSLError as err: |
| 1391 | if err.args[0] == ssl.SSL_ERROR_WANT_READ: |
| 1392 | self._handshake_reading = True |
| 1393 | return |
| 1394 | elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: |
| 1395 | self._handshake_writing = True |
| 1396 | return |
| 1397 | elif err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN): |
| 1398 | return self.close(exc_info=err) |
no outgoing calls