Skip to content

Commit 56e8e68

Browse files
committed
extmod/asyncio/stream.py: Add ipv6 support to start_server().
Ensures that the underlying socket is opened with the correct protocol as parsed by getaddrinfo(). Signed-off-by: Andrew Leech <[email protected]>
1 parent baa13da commit 56e8e68

File tree

3 files changed

+154
-3
lines changed

3 files changed

+154
-3
lines changed

extmod/asyncio/stream.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,11 @@ async def start_server(cb, host, port, backlog=5, ssl=None):
180180
import socket
181181

182182
# Create and bind server socket.
183-
host = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
184-
s = socket.socket()
183+
addr_info = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
184+
s = socket.socket(addr_info[0]) # Use address family from getaddrinfo
185185
s.setblocking(False)
186186
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
187-
s.bind(host[-1])
187+
s.bind(addr_info[-1])
188188
s.listen(backlog)
189189

190190
# Create and return server object and task.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Test asyncio TCP server and client using start_server() and open_connection() with IPv6
2+
3+
try:
4+
import asyncio
5+
import socket
6+
except ImportError:
7+
print("SKIP")
8+
raise SystemExit
9+
10+
try:
11+
# Check if IPv6 is supported
12+
socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
13+
except (AttributeError, OSError):
14+
print("SKIP")
15+
raise SystemExit
16+
17+
PORT = 8001 # Different from other tests to avoid conflicts
18+
19+
20+
async def handle_connection(reader, writer):
21+
# Test that peername exists
22+
peer = writer.get_extra_info("peername")
23+
print("peer connected")
24+
25+
data = await reader.read(100)
26+
print("echo:", data)
27+
writer.write(data)
28+
await writer.drain()
29+
30+
print("close")
31+
writer.close()
32+
await writer.wait_closed()
33+
34+
print("done")
35+
ev.set()
36+
37+
38+
async def tcp_server_ipv6():
39+
global ev
40+
ev = asyncio.Event()
41+
42+
# Start server with IPv6 address
43+
server = await asyncio.start_server(handle_connection, "::", PORT)
44+
print("ipv6 server running")
45+
multitest.next()
46+
47+
async with server:
48+
await asyncio.wait_for(ev.wait(), 10)
49+
50+
51+
async def tcp_client_ipv6(message):
52+
# Connect to the IPv6 server
53+
reader, writer = await asyncio.open_connection(IPV6, PORT)
54+
print("write:", message)
55+
writer.write(message)
56+
await writer.drain()
57+
58+
data = await reader.read(100)
59+
print("read:", data)
60+
assert data == message, "Data mismatch"
61+
62+
63+
def instance0():
64+
# Get the IPv6 address using the new parameter
65+
ipv6 = multitest.get_network_ip(ipv6=True)
66+
multitest.globals(IPV6=ipv6)
67+
asyncio.run(tcp_server_ipv6())
68+
69+
70+
def instance1():
71+
multitest.next()
72+
asyncio.run(tcp_client_ipv6(b"ipv6 client data"))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Test asyncio.start_server() with IPv6 address
2+
3+
try:
4+
import asyncio
5+
import socket
6+
except ImportError:
7+
print("SKIP")
8+
raise SystemExit
9+
10+
try:
11+
# Check if IPv6 is supported
12+
socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
13+
except (AttributeError, OSError):
14+
print("SKIP")
15+
raise SystemExit
16+
17+
PORT = 8000
18+
19+
20+
async def handle_connection(reader, writer):
21+
data = await reader.read(100)
22+
print("echo:", data)
23+
writer.write(data)
24+
await writer.drain()
25+
26+
print("close")
27+
writer.close()
28+
await writer.wait_closed()
29+
30+
print("done")
31+
global server_done
32+
server_done = True
33+
34+
35+
async def test_ipv6_server():
36+
global server_done
37+
server_done = False
38+
39+
# Start server with IPv6 address
40+
print("create ipv6 server")
41+
server = await asyncio.start_server(handle_connection, "::", PORT)
42+
print("server running")
43+
44+
try:
45+
# Connect with IPv6 client
46+
print("connect to ipv6 server")
47+
reader, writer = await asyncio.open_connection("::", PORT)
48+
49+
# Send test data
50+
test_msg = b"ipv6 test data"
51+
print("write:", test_msg)
52+
writer.write(test_msg)
53+
await writer.drain()
54+
55+
# Read response
56+
data = await reader.read(100)
57+
print("read:", data)
58+
assert data == test_msg, "Data mismatch"
59+
60+
# Close client connection
61+
print("close client")
62+
writer.close()
63+
await writer.wait_closed()
64+
65+
# Wait for server to complete handling
66+
while not server_done:
67+
await asyncio.sleep(0.1)
68+
69+
finally:
70+
# Ensure server is closed
71+
print("close server")
72+
server.close()
73+
await server.wait_closed()
74+
75+
print("test passed")
76+
77+
78+
# Run the test
79+
asyncio.run(test_ipv6_server())

0 commit comments

Comments
 (0)