summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio
diff options
context:
space:
mode:
authorYury Selivanov <yury@magic.io>2017-06-10 14:00:45 (GMT)
committerGitHub <noreply@github.com>2017-06-10 14:00:45 (GMT)
commit6e14fd2a14cef6ea0709ad234ab41198c2195591 (patch)
tree3ae3a8b355ad06737157de4504f634f80da9612c /Lib/asyncio
parent911068e250ee2b0847ca78d9ff527e0d6bf94551 (diff)
downloadcpython-6e14fd2a14cef6ea0709ad234ab41198c2195591.zip
cpython-6e14fd2a14cef6ea0709ad234ab41198c2195591.tar.gz
cpython-6e14fd2a14cef6ea0709ad234ab41198c2195591.tar.bz2
[3.6] bpo-29406: asyncio SSL contexts leak sockets after calling close with certain servers (GH-409) (#2062)
* bpo-29406: asyncio SSL contexts leak sockets after calling close with certain servers (#409) (cherry picked from commit a608d2d5a7f1aabe9bcbfc220135c5e126189390) * [3.6] bpo-29406: asyncio SSL contexts leak sockets after calling close with certain servers (GH-409) * asyncio SSL contexts leak sockets after calling close with certain servers * cleanup _shutdown_timeout_handle on _fatal_error. (cherry picked from commit a608d2d5a7f1aabe9bcbfc220135c5e126189390)
Diffstat (limited to 'Lib/asyncio')
-rw-r--r--Lib/asyncio/sslproto.py24
1 files changed, 23 insertions, 1 deletions
diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py
index 7948c4c..3b1eb99 100644
--- a/Lib/asyncio/sslproto.py
+++ b/Lib/asyncio/sslproto.py
@@ -7,6 +7,7 @@ except ImportError: # pragma: no cover
from . import base_events
from . import compat
+from . import futures
from . import protocols
from . import transports
from .log import logger
@@ -412,7 +413,7 @@ class SSLProtocol(protocols.Protocol):
def __init__(self, loop, app_protocol, sslcontext, waiter,
server_side=False, server_hostname=None,
- call_connection_made=True):
+ call_connection_made=True, shutdown_timeout=5.0):
if ssl is None:
raise RuntimeError('stdlib ssl module not available')
@@ -443,6 +444,8 @@ class SSLProtocol(protocols.Protocol):
self._session_established = False
self._in_handshake = False
self._in_shutdown = False
+ self._shutdown_timeout = shutdown_timeout
+ self._shutdown_timeout_handle = None
# transport, ex: SelectorSocketTransport
self._transport = None
self._call_connection_made = call_connection_made
@@ -557,6 +560,15 @@ class SSLProtocol(protocols.Protocol):
self._in_shutdown = True
self._write_appdata(b'')
+ if self._shutdown_timeout is not None:
+ self._shutdown_timeout_handle = self._loop.call_later(
+ self._shutdown_timeout, self._on_shutdown_timeout)
+
+ def _on_shutdown_timeout(self):
+ if self._transport is not None:
+ self._fatal_error(
+ futures.TimeoutError(), 'Can not complete shitdown operation')
+
def _write_appdata(self, data):
self._write_backlog.append((data, 0))
self._write_buffer_size += len(data)
@@ -684,12 +696,22 @@ class SSLProtocol(protocols.Protocol):
})
if self._transport:
self._transport._force_close(exc)
+ self._transport = None
+
+ if self._shutdown_timeout_handle is not None:
+ self._shutdown_timeout_handle.cancel()
+ self._shutdown_timeout_handle = None
def _finalize(self):
self._sslpipe = None
if self._transport is not None:
self._transport.close()
+ self._transport = None
+
+ if self._shutdown_timeout_handle is not None:
+ self._shutdown_timeout_handle.cancel()
+ self._shutdown_timeout_handle = None
def _abort(self):
try: