Skip to content

Commit

Permalink
Enable IPv4/IPv6 dual stack support on Windows
Browse files Browse the repository at this point in the history
Actually, Windows supports dual stack sockets, but does not enable it by default.
  • Loading branch information
msoxzw authored and jlaine committed Mar 25, 2022
1 parent 2938289 commit ac99379
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 9 deletions.
25 changes: 16 additions & 9 deletions src/aioquic/asyncio/client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import asyncio
import ipaddress
import socket
import sys
from contextlib import asynccontextmanager
from typing import AsyncGenerator, Callable, Optional, cast

Expand All @@ -12,6 +11,10 @@

__all__ = ["connect"]

# keep compatibility for Python 3.7 on Windows
if not hasattr(socket, "IPPROTO_IPV6"):
socket.IPPROTO_IPV6 = 41


@asynccontextmanager
async def connect(
Expand Down Expand Up @@ -61,13 +64,7 @@ async def connect(
infos = await loop.getaddrinfo(host, port, type=socket.SOCK_DGRAM)
addr = infos[0][4]
if len(addr) == 2:
# determine behaviour for IPv4
if sys.platform == "win32":
# on Windows, we must use an IPv4 socket to reach an IPv4 host
local_host = "0.0.0.0"
else:
# other platforms support dual-stack sockets
addr = ("::ffff:" + addr[0], addr[1], 0, 0)
addr = ("::ffff:" + addr[0], addr[1], 0, 0)

# prepare QUIC connection
if configuration is None:
Expand All @@ -78,10 +75,20 @@ async def connect(
configuration=configuration, session_ticket_handler=session_ticket_handler
)

# explicitly enable IPv4/IPv6 dual stack
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
completed = False
try:
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
sock.bind((local_host, local_port, 0, 0))
completed = True
finally:
if not completed:
sock.close()
# connect
transport, protocol = await loop.create_datagram_endpoint(
lambda: create_protocol(connection, stream_handler=stream_handler),
local_addr=(local_host, local_port),
sock=sock,
)
protocol = cast(QuicConnectionProtocol, protocol)
try:
Expand Down
5 changes: 5 additions & 0 deletions tests/test_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,11 @@ async def test_connect_local_port(self):
response = await self.run_client(local_port=3456, port=server_port)
self.assertEqual(response, b"gnip")

@asynctest
async def test_connect_local_port_bind(self):
with self.assertRaises(OverflowError):
await self.run_client(local_port=-1, port=self.bogus_port)

@asynctest
async def test_change_connection_id(self):
async with self.run_server() as server_port:
Expand Down

0 comments on commit ac99379

Please sign in to comment.