Skip to content

Commit 6227c48

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 <andrew.leech@planetinnovation.com.au>
1 parent 8ca1283 commit 6227c48

File tree

3 files changed

+154
-3
lines changed

3 files changed

+154
-3
lines changed

extmod/asyncio/stream.py

Lines changed: 3 additions & 3 deletions
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.
Lines changed: 72 additions & 0 deletions
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"))
Lines changed: 79 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy