We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
TCP connection fails on systems without IPv6 support when connecting to a host that has an IPv6 address
`getaddrinfo` will return IPv6 addresses when the system doesn't support it, and Tornado will then fail to connect to the IPv6 address with this error (I get [a report for my project here](https://github.com/lilydjwg/nvchecker/issues/41)):

```
OSError: [Errno 97] Address family not supported by protocol
```

I see in #593 `AI_ADDRCONFIG` was removed from `bind_sockets`, and in #823 Tornado just ignores the unsupported protocol. But this is about `connect`, not `bind`. What do you think, to use `AI_ADDRCONFIG` or just ignore the error? There's currently no way to pass the flags to resolvers though.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `tornado/tcpclient.py`
Content:
```
1 #!/usr/bin/env python
2 #
3 # Copyright 2014 Facebook
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
8 #
9 #     http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
15 # under the License.
16 
17 """A non-blocking TCP connection factory.
18 """
19 from __future__ import absolute_import, division, print_function, with_statement
20 
21 import functools
22 import socket
23 
24 from tornado.concurrent import Future
25 from tornado.ioloop import IOLoop
26 from tornado.iostream import IOStream
27 from tornado import gen
28 from tornado.netutil import Resolver
29 
30 _INITIAL_CONNECT_TIMEOUT = 0.3
31 
32 
33 class _Connector(object):
34     """A stateless implementation of the "Happy Eyeballs" algorithm.
35 
36     "Happy Eyeballs" is documented in RFC6555 as the recommended practice
37     for when both IPv4 and IPv6 addresses are available.
38 
39     In this implementation, we partition the addresses by family, and
40     make the first connection attempt to whichever address was
41     returned first by ``getaddrinfo``.  If that connection fails or
42     times out, we begin a connection in parallel to the first address
43     of the other family.  If there are additional failures we retry
44     with other addresses, keeping one connection attempt per family
45     in flight at a time.
46 
47     http://tools.ietf.org/html/rfc6555
48 
49     """
50     def __init__(self, addrinfo, io_loop, connect):
51         self.io_loop = io_loop
52         self.connect = connect
53 
54         self.future = Future()
55         self.timeout = None
56         self.last_error = None
57         self.remaining = len(addrinfo)
58         self.primary_addrs, self.secondary_addrs = self.split(addrinfo)
59 
60     @staticmethod
61     def split(addrinfo):
62         """Partition the ``addrinfo`` list by address family.
63 
64         Returns two lists.  The first list contains the first entry from
65         ``addrinfo`` and all others with the same family, and the
66         second list contains all other addresses (normally one list will
67         be AF_INET and the other AF_INET6, although non-standard resolvers
68         may return additional families).
69         """
70         primary = []
71         secondary = []
72         primary_af = addrinfo[0][0]
73         for af, addr in addrinfo:
74             if af == primary_af:
75                 primary.append((af, addr))
76             else:
77                 secondary.append((af, addr))
78         return primary, secondary
79 
80     def start(self, timeout=_INITIAL_CONNECT_TIMEOUT):
81         self.try_connect(iter(self.primary_addrs))
82         self.set_timout(timeout)
83         return self.future
84 
85     def try_connect(self, addrs):
86         try:
87             af, addr = next(addrs)
88         except StopIteration:
89             # We've reached the end of our queue, but the other queue
90             # might still be working.  Send a final error on the future
91             # only when both queues are finished.
92             if self.remaining == 0 and not self.future.done():
93                 self.future.set_exception(self.last_error or
94                                           IOError("connection failed"))
95             return
96         future = self.connect(af, addr)
97         future.add_done_callback(functools.partial(self.on_connect_done,
98                                                    addrs, af, addr))
99 
100     def on_connect_done(self, addrs, af, addr, future):
101         self.remaining -= 1
102         try:
103             stream = future.result()
104         except Exception as e:
105             if self.future.done():
106                 return
107             # Error: try again (but remember what happened so we have an
108             # error to raise in the end)
109             self.last_error = e
110             self.try_connect(addrs)
111             if self.timeout is not None:
112                 # If the first attempt failed, don't wait for the
113                 # timeout to try an address from the secondary queue.
114                 self.io_loop.remove_timeout(self.timeout)
115                 self.on_timeout()
116             return
117         self.clear_timeout()
118         if self.future.done():
119             # This is a late arrival; just drop it.
120             stream.close()
121         else:
122             self.future.set_result((af, addr, stream))
123 
124     def set_timout(self, timeout):
125         self.timeout = self.io_loop.add_timeout(self.io_loop.time() + timeout,
126                                                 self.on_timeout)
127 
128     def on_timeout(self):
129         self.timeout = None
130         self.try_connect(iter(self.secondary_addrs))
131 
132     def clear_timeout(self):
133         if self.timeout is not None:
134             self.io_loop.remove_timeout(self.timeout)
135 
136 
137 class TCPClient(object):
138     """A non-blocking TCP connection factory.
139 
140     .. versionchanged:: 4.1
141        The ``io_loop`` argument is deprecated.
142     """
143     def __init__(self, resolver=None, io_loop=None):
144         self.io_loop = io_loop or IOLoop.current()
145         if resolver is not None:
146             self.resolver = resolver
147             self._own_resolver = False
148         else:
149             self.resolver = Resolver(io_loop=io_loop)
150             self._own_resolver = True
151 
152     def close(self):
153         if self._own_resolver:
154             self.resolver.close()
155 
156     @gen.coroutine
157     def connect(self, host, port, af=socket.AF_UNSPEC, ssl_options=None,
158                 max_buffer_size=None):
159         """Connect to the given host and port.
160 
161         Asynchronously returns an `.IOStream` (or `.SSLIOStream` if
162         ``ssl_options`` is not None).
163         """
164         addrinfo = yield self.resolver.resolve(host, port, af)
165         connector = _Connector(
166             addrinfo, self.io_loop,
167             functools.partial(self._create_stream, max_buffer_size))
168         af, addr, stream = yield connector.start()
169         # TODO: For better performance we could cache the (af, addr)
170         # information here and re-use it on subsequent connections to
171         # the same host. (http://tools.ietf.org/html/rfc6555#section-4.2)
172         if ssl_options is not None:
173             stream = yield stream.start_tls(False, ssl_options=ssl_options,
174                                             server_hostname=host)
175         raise gen.Return(stream)
176 
177     def _create_stream(self, max_buffer_size, af, addr):
178         # Always connect in plaintext; we'll convert to ssl if necessary
179         # after one connection has completed.
180         stream = IOStream(socket.socket(af),
181                           io_loop=self.io_loop,
182                           max_buffer_size=max_buffer_size)
183         return stream.connect(addr)
184
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/tornado/tcpclient.py b/tornado/tcpclient.py
--- a/tornado/tcpclient.py
+++ b/tornado/tcpclient.py
@@ -177,7 +177,13 @@
     def _create_stream(self, max_buffer_size, af, addr):
         # Always connect in plaintext; we'll convert to ssl if necessary
         # after one connection has completed.
-        stream = IOStream(socket.socket(af),
-                          io_loop=self.io_loop,
-                          max_buffer_size=max_buffer_size)
-        return stream.connect(addr)
+        try:
+            stream = IOStream(socket.socket(af),
+                            io_loop=self.io_loop,
+                            max_buffer_size=max_buffer_size)
+        except socket.error as e:
+            fu = Future()
+            fu.set_exception(e)
+            return fu
+        else:
+            return stream.connect(addr)

{"golden_diff": "diff --git a/tornado/tcpclient.py b/tornado/tcpclient.py\n--- a/tornado/tcpclient.py\n+++ b/tornado/tcpclient.py\n@@ -177,7 +177,13 @@\n     def _create_stream(self, max_buffer_size, af, addr):\n         # Always connect in plaintext; we'll convert to ssl if necessary\n         # after one connection has completed.\n-        stream = IOStream(socket.socket(af),\n-                          io_loop=self.io_loop,\n-                          max_buffer_size=max_buffer_size)\n-        return stream.connect(addr)\n+        try:\n+            stream = IOStream(socket.socket(af),\n+                            io_loop=self.io_loop,\n+                            max_buffer_size=max_buffer_size)\n+        except socket.error as e:\n+            fu = Future()\n+            fu.set_exception(e)\n+            return fu\n+        else:\n+            return stream.connect(addr)\n", "issue": "TCP connection fails on systems without IPv6 support when connecting to a host that has an IPv6 address\n`getaddrinfo` will return IPv6 addresses when the system doesn't support it, and Tornado will then fail to connect to the IPv6 address with this error (I get [a report for my project here](https://github.com/lilydjwg/nvchecker/issues/41)):\n\n```\nOSError: [Errno 97] Address family not supported by protocol\n```\n\nI see in #593 `AI_ADDRCONFIG` was removed from `bind_sockets`, and in #823 Tornado just ignores the unsupported protocol. But this is about `connect`, not `bind`. What do you think, to use `AI_ADDRCONFIG` or just ignore the error? There's currently no way to pass the flags to resolvers though.\n\n", "before_files": [{"content": "#!/usr/bin/env python\n#\n# Copyright 2014 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\n\"\"\"A non-blocking TCP connection factory.\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, with_statement\n\nimport functools\nimport socket\n\nfrom tornado.concurrent import Future\nfrom tornado.ioloop import IOLoop\nfrom tornado.iostream import IOStream\nfrom tornado import gen\nfrom tornado.netutil import Resolver\n\n_INITIAL_CONNECT_TIMEOUT = 0.3\n\n\nclass _Connector(object):\n    \"\"\"A stateless implementation of the \"Happy Eyeballs\" algorithm.\n\n    \"Happy Eyeballs\" is documented in RFC6555 as the recommended practice\n    for when both IPv4 and IPv6 addresses are available.\n\n    In this implementation, we partition the addresses by family, and\n    make the first connection attempt to whichever address was\n    returned first by ``getaddrinfo``.  If that connection fails or\n    times out, we begin a connection in parallel to the first address\n    of the other family.  If there are additional failures we retry\n    with other addresses, keeping one connection attempt per family\n    in flight at a time.\n\n    http://tools.ietf.org/html/rfc6555\n\n    \"\"\"\n    def __init__(self, addrinfo, io_loop, connect):\n        self.io_loop = io_loop\n        self.connect = connect\n\n        self.future = Future()\n        self.timeout = None\n        self.last_error = None\n        self.remaining = len(addrinfo)\n        self.primary_addrs, self.secondary_addrs = self.split(addrinfo)\n\n    @staticmethod\n    def split(addrinfo):\n        \"\"\"Partition the ``addrinfo`` list by address family.\n\n        Returns two lists.  The first list contains the first entry from\n        ``addrinfo`` and all others with the same family, and the\n        second list contains all other addresses (normally one list will\n        be AF_INET and the other AF_INET6, although non-standard resolvers\n        may return additional families).\n        \"\"\"\n        primary = []\n        secondary = []\n        primary_af = addrinfo[0][0]\n        for af, addr in addrinfo:\n            if af == primary_af:\n                primary.append((af, addr))\n            else:\n                secondary.append((af, addr))\n        return primary, secondary\n\n    def start(self, timeout=_INITIAL_CONNECT_TIMEOUT):\n        self.try_connect(iter(self.primary_addrs))\n        self.set_timout(timeout)\n        return self.future\n\n    def try_connect(self, addrs):\n        try:\n            af, addr = next(addrs)\n        except StopIteration:\n            # We've reached the end of our queue, but the other queue\n            # might still be working.  Send a final error on the future\n            # only when both queues are finished.\n            if self.remaining == 0 and not self.future.done():\n                self.future.set_exception(self.last_error or\n                                          IOError(\"connection failed\"))\n            return\n        future = self.connect(af, addr)\n        future.add_done_callback(functools.partial(self.on_connect_done,\n                                                   addrs, af, addr))\n\n    def on_connect_done(self, addrs, af, addr, future):\n        self.remaining -= 1\n        try:\n            stream = future.result()\n        except Exception as e:\n            if self.future.done():\n                return\n            # Error: try again (but remember what happened so we have an\n            # error to raise in the end)\n            self.last_error = e\n            self.try_connect(addrs)\n            if self.timeout is not None:\n                # If the first attempt failed, don't wait for the\n                # timeout to try an address from the secondary queue.\n                self.io_loop.remove_timeout(self.timeout)\n                self.on_timeout()\n            return\n        self.clear_timeout()\n        if self.future.done():\n            # This is a late arrival; just drop it.\n            stream.close()\n        else:\n            self.future.set_result((af, addr, stream))\n\n    def set_timout(self, timeout):\n        self.timeout = self.io_loop.add_timeout(self.io_loop.time() + timeout,\n                                                self.on_timeout)\n\n    def on_timeout(self):\n        self.timeout = None\n        self.try_connect(iter(self.secondary_addrs))\n\n    def clear_timeout(self):\n        if self.timeout is not None:\n            self.io_loop.remove_timeout(self.timeout)\n\n\nclass TCPClient(object):\n    \"\"\"A non-blocking TCP connection factory.\n\n    .. versionchanged:: 4.1\n       The ``io_loop`` argument is deprecated.\n    \"\"\"\n    def __init__(self, resolver=None, io_loop=None):\n        self.io_loop = io_loop or IOLoop.current()\n        if resolver is not None:\n            self.resolver = resolver\n            self._own_resolver = False\n        else:\n            self.resolver = Resolver(io_loop=io_loop)\n            self._own_resolver = True\n\n    def close(self):\n        if self._own_resolver:\n            self.resolver.close()\n\n    @gen.coroutine\n    def connect(self, host, port, af=socket.AF_UNSPEC, ssl_options=None,\n                max_buffer_size=None):\n        \"\"\"Connect to the given host and port.\n\n        Asynchronously returns an `.IOStream` (or `.SSLIOStream` if\n        ``ssl_options`` is not None).\n        \"\"\"\n        addrinfo = yield self.resolver.resolve(host, port, af)\n        connector = _Connector(\n            addrinfo, self.io_loop,\n            functools.partial(self._create_stream, max_buffer_size))\n        af, addr, stream = yield connector.start()\n        # TODO: For better performance we could cache the (af, addr)\n        # information here and re-use it on subsequent connections to\n        # the same host. (http://tools.ietf.org/html/rfc6555#section-4.2)\n        if ssl_options is not None:\n            stream = yield stream.start_tls(False, ssl_options=ssl_options,\n                                            server_hostname=host)\n        raise gen.Return(stream)\n\n    def _create_stream(self, max_buffer_size, af, addr):\n        # Always connect in plaintext; we'll convert to ssl if necessary\n        # after one connection has completed.\n        stream = IOStream(socket.socket(af),\n                          io_loop=self.io_loop,\n                          max_buffer_size=max_buffer_size)\n        return stream.connect(addr)\n", "path": "tornado/tcpclient.py"}], "after_files": [{"content": "#!/usr/bin/env python\n#\n# Copyright 2014 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\n\"\"\"A non-blocking TCP connection factory.\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, with_statement\n\nimport functools\nimport socket\n\nfrom tornado.concurrent import Future\nfrom tornado.ioloop import IOLoop\nfrom tornado.iostream import IOStream\nfrom tornado import gen\nfrom tornado.netutil import Resolver\n\n_INITIAL_CONNECT_TIMEOUT = 0.3\n\n\nclass _Connector(object):\n    \"\"\"A stateless implementation of the \"Happy Eyeballs\" algorithm.\n\n    \"Happy Eyeballs\" is documented in RFC6555 as the recommended practice\n    for when both IPv4 and IPv6 addresses are available.\n\n    In this implementation, we partition the addresses by family, and\n    make the first connection attempt to whichever address was\n    returned first by ``getaddrinfo``.  If that connection fails or\n    times out, we begin a connection in parallel to the first address\n    of the other family.  If there are additional failures we retry\n    with other addresses, keeping one connection attempt per family\n    in flight at a time.\n\n    http://tools.ietf.org/html/rfc6555\n\n    \"\"\"\n    def __init__(self, addrinfo, io_loop, connect):\n        self.io_loop = io_loop\n        self.connect = connect\n\n        self.future = Future()\n        self.timeout = None\n        self.last_error = None\n        self.remaining = len(addrinfo)\n        self.primary_addrs, self.secondary_addrs = self.split(addrinfo)\n\n    @staticmethod\n    def split(addrinfo):\n        \"\"\"Partition the ``addrinfo`` list by address family.\n\n        Returns two lists.  The first list contains the first entry from\n        ``addrinfo`` and all others with the same family, and the\n        second list contains all other addresses (normally one list will\n        be AF_INET and the other AF_INET6, although non-standard resolvers\n        may return additional families).\n        \"\"\"\n        primary = []\n        secondary = []\n        primary_af = addrinfo[0][0]\n        for af, addr in addrinfo:\n            if af == primary_af:\n                primary.append((af, addr))\n            else:\n                secondary.append((af, addr))\n        return primary, secondary\n\n    def start(self, timeout=_INITIAL_CONNECT_TIMEOUT):\n        self.try_connect(iter(self.primary_addrs))\n        self.set_timout(timeout)\n        return self.future\n\n    def try_connect(self, addrs):\n        try:\n            af, addr = next(addrs)\n        except StopIteration:\n            # We've reached the end of our queue, but the other queue\n            # might still be working.  Send a final error on the future\n            # only when both queues are finished.\n            if self.remaining == 0 and not self.future.done():\n                self.future.set_exception(self.last_error or\n                                          IOError(\"connection failed\"))\n            return\n        future = self.connect(af, addr)\n        future.add_done_callback(functools.partial(self.on_connect_done,\n                                                   addrs, af, addr))\n\n    def on_connect_done(self, addrs, af, addr, future):\n        self.remaining -= 1\n        try:\n            stream = future.result()\n        except Exception as e:\n            if self.future.done():\n                return\n            # Error: try again (but remember what happened so we have an\n            # error to raise in the end)\n            self.last_error = e\n            self.try_connect(addrs)\n            if self.timeout is not None:\n                # If the first attempt failed, don't wait for the\n                # timeout to try an address from the secondary queue.\n                self.io_loop.remove_timeout(self.timeout)\n                self.on_timeout()\n            return\n        self.clear_timeout()\n        if self.future.done():\n            # This is a late arrival; just drop it.\n            stream.close()\n        else:\n            self.future.set_result((af, addr, stream))\n\n    def set_timout(self, timeout):\n        self.timeout = self.io_loop.add_timeout(self.io_loop.time() + timeout,\n                                                self.on_timeout)\n\n    def on_timeout(self):\n        self.timeout = None\n        self.try_connect(iter(self.secondary_addrs))\n\n    def clear_timeout(self):\n        if self.timeout is not None:\n            self.io_loop.remove_timeout(self.timeout)\n\n\nclass TCPClient(object):\n    \"\"\"A non-blocking TCP connection factory.\n\n    .. versionchanged:: 4.1\n       The ``io_loop`` argument is deprecated.\n    \"\"\"\n    def __init__(self, resolver=None, io_loop=None):\n        self.io_loop = io_loop or IOLoop.current()\n        if resolver is not None:\n            self.resolver = resolver\n            self._own_resolver = False\n        else:\n            self.resolver = Resolver(io_loop=io_loop)\n            self._own_resolver = True\n\n    def close(self):\n        if self._own_resolver:\n            self.resolver.close()\n\n    @gen.coroutine\n    def connect(self, host, port, af=socket.AF_UNSPEC, ssl_options=None,\n                max_buffer_size=None):\n        \"\"\"Connect to the given host and port.\n\n        Asynchronously returns an `.IOStream` (or `.SSLIOStream` if\n        ``ssl_options`` is not None).\n        \"\"\"\n        addrinfo = yield self.resolver.resolve(host, port, af)\n        connector = _Connector(\n            addrinfo, self.io_loop,\n            functools.partial(self._create_stream, max_buffer_size))\n        af, addr, stream = yield connector.start()\n        # TODO: For better performance we could cache the (af, addr)\n        # information here and re-use it on subsequent connections to\n        # the same host. (http://tools.ietf.org/html/rfc6555#section-4.2)\n        if ssl_options is not None:\n            stream = yield stream.start_tls(False, ssl_options=ssl_options,\n                                            server_hostname=host)\n        raise gen.Return(stream)\n\n    def _create_stream(self, max_buffer_size, af, addr):\n        # Always connect in plaintext; we'll convert to ssl if necessary\n        # after one connection has completed.\n        try:\n            stream = IOStream(socket.socket(af),\n                            io_loop=self.io_loop,\n                            max_buffer_size=max_buffer_size)\n        except socket.error as e:\n            fu = Future()\n            fu.set_exception(e)\n            return fu\n        else:\n            return stream.connect(addr)\n", "path": "tornado/tcpclient.py"}]}