|
25 | 25 | import socket
|
26 | 26 | from types import TracebackType
|
27 | 27 | from typing import TYPE_CHECKING, AnyStr, Callable, Generic, List, Optional
|
28 |
| -from typing import Sequence, Tuple, Type, Union |
| 28 | +from typing import Sequence, Set, Tuple, Type, Union |
29 | 29 | from typing_extensions import Self
|
30 | 30 |
|
31 | 31 | from .forward import SSHForwarderCoro
|
@@ -285,9 +285,19 @@ async def create_tcp_local_listener(
|
285 | 285 | if not addrinfo: # pragma: no cover
|
286 | 286 | raise OSError('getaddrinfo() returned empty list')
|
287 | 287 |
|
| 288 | + seen_addrinfo: Set[Tuple] = set() |
288 | 289 | servers: List[asyncio.AbstractServer] = []
|
289 | 290 |
|
290 |
| - for family, socktype, proto, _, sa in addrinfo: |
| 291 | + for addrinfo_entry in addrinfo: |
| 292 | + # Work around an issue where getaddrinfo() on some systems may |
| 293 | + # return duplicate results, causing bind to fail. |
| 294 | + if addrinfo_entry in seen_addrinfo: # pragma: no cover |
| 295 | + continue |
| 296 | + |
| 297 | + seen_addrinfo.add(addrinfo_entry) |
| 298 | + |
| 299 | + family, socktype, proto, _, sa = addrinfo_entry |
| 300 | + |
291 | 301 | try:
|
292 | 302 | sock = socket.socket(family, socktype, proto)
|
293 | 303 | except OSError: # pragma: no cover
|
|
0 commit comments