diff -r 25028b0e1183 Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py Thu Jan 29 02:57:10 2015 +0100 +++ b/Lib/asyncio/base_events.py Thu Jan 29 03:03:13 2015 +0100 @@ -637,8 +637,10 @@ class BaseEventLoop(events.AbstractEvent try: yield from waiter - except: - transport.close() + except Exception as exc: + self.call_soon(protocol.connection_failed, transport, exc) + # only close the transport when connection_failed() has been called + self.call_soon(transport.close) raise return transport, protocol @@ -727,8 +729,10 @@ class BaseEventLoop(events.AbstractEvent try: yield from waiter - except: - transport.close() + except Exception as exc: + self.call_soon(protocol.connection_failed, transport, exc) + # only close the transport when connection_failed() has been called + self.call_soon(transport.close) raise return transport, protocol @@ -825,8 +829,10 @@ class BaseEventLoop(events.AbstractEvent try: yield from waiter - except: - transport.close() + except Exception as exc: + self.call_soon(protocol.connection_failed, transport, exc) + # only close the transport when connection_failed() has been called + self.call_soon(transport.close) raise if self._debug: @@ -842,8 +848,10 @@ class BaseEventLoop(events.AbstractEvent try: yield from waiter - except: - transport.close() + except Exception as exc: + self.call_soon(protocol.connection_failed, transport, exc) + # only close the transport when connection_failed() has been called + self.call_soon(transport.close) raise if self._debug: diff -r 25028b0e1183 Lib/asyncio/protocols.py --- a/Lib/asyncio/protocols.py Thu Jan 29 02:57:10 2015 +0100 +++ b/Lib/asyncio/protocols.py Thu Jan 29 03:03:13 2015 +0100 @@ -30,6 +30,14 @@ class BaseProtocol: aborted or closed). """ + def connection_failed(self, transport, exc): + """Called when the connection to the transport failed. + + This method is called by a server for an incoming client connection + when the creation of the transport failed, if the SSL handshake failed + for example. + """ + def pause_writing(self): """Called when the transport's buffer goes over the high-water mark. diff -r 25028b0e1183 Lib/asyncio/subprocess.py --- a/Lib/asyncio/subprocess.py Thu Jan 29 02:57:10 2015 +0100 +++ b/Lib/asyncio/subprocess.py Thu Jan 29 03:03:13 2015 +0100 @@ -223,8 +223,10 @@ def create_subprocess_shell(cmd, stdin=N stderr=stderr, **kwds) try: yield from protocol.waiter - except: - transport._kill_wait() + except Exception as exc: + loop.call_soon(protocol.connection_failed, transport, exc) + # only close the transport when connection_failed() has been called + loop.call_soon(transport._kill_wait) raise return Process(transport, protocol, loop) @@ -243,7 +245,9 @@ def create_subprocess_exec(program, *arg stderr=stderr, **kwds) try: yield from protocol.waiter - except: - transport._kill_wait() + except Exception as exc: + loop.call_soon(protocol.connection_failed, transport, exc) + # only close the transport when connection_failed() has been called + loop.call_soon(transport._kill_wait) raise return Process(transport, protocol, loop) diff -r 25028b0e1183 Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py Thu Jan 29 02:57:10 2015 +0100 +++ b/Lib/asyncio/unix_events.py Thu Jan 29 03:03:13 2015 +0100 @@ -179,8 +179,10 @@ class _UnixSelectorEventLoop(selector_ev extra=extra, **kwargs) try: yield from transp._post_init() - except: - transp.close() + except Exception as exc: + self.call_soon(protocol.connection_failed, transp, exc) + # only kill the process when connection_failed() has been called + self.call_soon(transp._kill_wait) raise watcher.add_child_handler(transp.get_pid(), self._child_watcher_callback, transp) diff -r 25028b0e1183 Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py Thu Jan 29 02:57:10 2015 +0100 +++ b/Lib/test/test_asyncio/test_subprocess.py Thu Jan 29 03:03:13 2015 +0100 @@ -279,10 +279,13 @@ class SubprocessMixin: with test_utils.disable_logger(): self.loop.run_until_complete(cancel_make_transport()) - def test_cancel_post_init(self): + def test_cancel_subprocess_post_init(self): + proto = mock.Mock() #asyncio.SubprocessProtocol + proto.connection_failed._is_coroutine = False + @asyncio.coroutine def cancel_make_transport(): - coro = self.loop.subprocess_exec(asyncio.SubprocessProtocol, + coro = self.loop.subprocess_exec(lambda: proto, *PROGRAM_BLOCKED) task = self.loop.create_task(coro) @@ -298,6 +301,8 @@ class SubprocessMixin: self.loop.run_until_complete(cancel_make_transport()) test_utils.run_briefly(self.loop) + self.assertTrue(proto.connection_failed.called) + if sys.platform != 'win32': # Unix