diff --git a/extmod/asyncio/stream.py b/extmod/asyncio/stream.py index cb0a804b5ed26..10d57ae8a1e22 100644 --- a/extmod/asyncio/stream.py +++ b/extmod/asyncio/stream.py @@ -180,11 +180,11 @@ async def start_server(cb, host, port, backlog=5, ssl=None): import socket # Create and bind server socket. - host = socket.getaddrinfo(host, port)[0] # TODO this is blocking! - s = socket.socket() + addr_info = socket.getaddrinfo(host, port)[0] # TODO this is blocking! + s = socket.socket(addr_info[0]) # Use address family from getaddrinfo s.setblocking(False) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - s.bind(host[-1]) + s.bind(addr_info[-1]) s.listen(backlog) # Create and return server object and task. diff --git a/tests/multi_net/asyncio_tcp_server_client_ipv6.py b/tests/multi_net/asyncio_tcp_server_client_ipv6.py new file mode 100644 index 0000000000000..df514fad209ea --- /dev/null +++ b/tests/multi_net/asyncio_tcp_server_client_ipv6.py @@ -0,0 +1,72 @@ +# Test asyncio TCP server and client using start_server() and open_connection() with IPv6 + +try: + import asyncio + import socket +except ImportError: + print("SKIP") + raise SystemExit + +try: + # Check if IPv6 is supported + socket.socket(socket.AF_INET6, socket.SOCK_STREAM) +except (AttributeError, OSError): + print("SKIP") + raise SystemExit + +PORT = 8001 # Different from other tests to avoid conflicts + + +async def handle_connection(reader, writer): + # Test that peername exists + peer = writer.get_extra_info("peername") + print("peer connected") + + data = await reader.read(100) + print("echo:", data) + writer.write(data) + await writer.drain() + + print("close") + writer.close() + await writer.wait_closed() + + print("done") + ev.set() + + +async def tcp_server_ipv6(): + global ev + ev = asyncio.Event() + + # Start server with IPv6 address + server = await asyncio.start_server(handle_connection, "::", PORT) + print("ipv6 server running") + multitest.next() + + async with server: + await asyncio.wait_for(ev.wait(), 10) + + +async def tcp_client_ipv6(message): + # Connect to the IPv6 server + reader, writer = await asyncio.open_connection(IPV6, PORT) + print("write:", message) + writer.write(message) + await writer.drain() + + data = await reader.read(100) + print("read:", data) + assert data == message, "Data mismatch" + + +def instance0(): + # Get the IPv6 address using the new parameter + ipv6 = multitest.get_network_ip(ipv6=True) + multitest.globals(IPV6=ipv6) + asyncio.run(tcp_server_ipv6()) + + +def instance1(): + multitest.next() + asyncio.run(tcp_client_ipv6(b"ipv6 client data")) diff --git a/tests/net_hosted/asyncio_start_server_ipv6.py b/tests/net_hosted/asyncio_start_server_ipv6.py new file mode 100644 index 0000000000000..c785a5d386214 --- /dev/null +++ b/tests/net_hosted/asyncio_start_server_ipv6.py @@ -0,0 +1,79 @@ +# Test asyncio.start_server() with IPv6 address + +try: + import asyncio + import socket +except ImportError: + print("SKIP") + raise SystemExit + +try: + # Check if IPv6 is supported + socket.socket(socket.AF_INET6, socket.SOCK_STREAM) +except (AttributeError, OSError): + print("SKIP") + raise SystemExit + +PORT = 8000 + + +async def handle_connection(reader, writer): + data = await reader.read(100) + print("echo:", data) + writer.write(data) + await writer.drain() + + print("close") + writer.close() + await writer.wait_closed() + + print("done") + global server_done + server_done = True + + +async def test_ipv6_server(): + global server_done + server_done = False + + # Start server with IPv6 address + print("create ipv6 server") + server = await asyncio.start_server(handle_connection, "::", PORT) + print("server running") + + try: + # Connect with IPv6 client + print("connect to ipv6 server") + reader, writer = await asyncio.open_connection("::", PORT) + + # Send test data + test_msg = b"ipv6 test data" + print("write:", test_msg) + writer.write(test_msg) + await writer.drain() + + # Read response + data = await reader.read(100) + print("read:", data) + assert data == test_msg, "Data mismatch" + + # Close client connection + print("close client") + writer.close() + await writer.wait_closed() + + # Wait for server to complete handling + while not server_done: + await asyncio.sleep(0.1) + + finally: + # Ensure server is closed + print("close server") + server.close() + await server.wait_closed() + + print("test passed") + + +# Run the test +asyncio.run(test_ipv6_server()) diff --git a/tests/run-multitests.py b/tests/run-multitests.py index 387eec7018bb3..d3d541d612816 100755 --- a/tests/run-multitests.py +++ b/tests/run-multitests.py @@ -79,19 +79,59 @@ def globals(**gs): print("SET {{}} = {{!r}}".format(g, gs[g])) multitest.flush() @staticmethod - def get_network_ip(): + def _get_ip_from_ifconfig(_nic, ipv6=False): + # Helper to get IP address from an interface object using appropriate format + addr_type = 'addr6' if ipv6 else 'addr4' + + # First try newer format with addr type parameter try: - ip = nic.ifconfig()[0] + ip = _nic.ifconfig(addr_type) + if isinstance(ip, tuple) and len(ip) > 0: + return ip[0] + return ip except: - try: - import network - if hasattr(network, "WLAN"): - ip = network.WLAN().ifconfig()[0] - else: - ip = network.LAN().ifconfig()[0] - except: - ip = HOST_IP - return ip + # Fallback to legacy format, but only for IPv4 + if not ipv6: + try: + return _nic.ifconfig()[0] # Legacy format + except: + pass + return None + @staticmethod + def get_network_ip(ipv6=False): + # Try with direct nic object if available + try: + if 'nic' in globals(): + ip = multitest._get_ip_from_ifconfig(nic, ipv6) + if ip: + return ip + except: + pass + + # Find active network interface + try: + import network + for attr_name in dir(network): + if attr_name.startswith('__'): + continue + try: + net_class = getattr(network, attr_name) + if hasattr(net_class, 'active'): + try: + net_obj = net_class() + if net_obj.active() and hasattr(net_obj, 'ifconfig'): + ip = multitest._get_ip_from_ifconfig(net_obj, ipv6) + if ip: + return ip + except: + pass + except: + pass + except: + pass + + # Fallback to host IP + return HOST_IP6 if ipv6 else HOST_IP @staticmethod def expect_reboot(resume, delay_ms=0): print("WAIT_FOR_REBOOT", resume, delay_ms) @@ -130,6 +170,24 @@ def get_host_ip(_ip_cache=[]): return _ip_cache[0] +def get_host_ipv6(_ipv6_cache=[]): + if not _ipv6_cache: + try: + import socket + + # Try to find an IPv6 address by creating an IPv6 socket + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + # Connect to IPv6 Google DNS server to get our IPv6 address + s.connect(("2001:4860:4860::8888", 80)) + addr = s.getsockname()[0] + s.close() + _ipv6_cache.append(addr) + except: + # Fallback to localhost if unable to determine IPv6 address + _ipv6_cache.append("::1") + return _ipv6_cache[0] + + class PyInstance: def __init__(self): pass @@ -330,12 +388,19 @@ def run_test_on_instances(test_file, num_instances, instances): output = [[] for _ in range(num_instances)] output_metrics = [] - # If the test calls get_network_ip() then inject HOST_IP so that devices can know - # the IP address of the host. Do this lazily to not require a TCP/IP connection - # on the host if it's not needed. + # If the test calls get_network_ip() or get_network_ipv6() then inject HOST_IP and HOST_IP6 + # so that devices can know the IP addresses of the host. Do this lazily to not require + # a TCP/IP connection on the host if it's not needed. with open(test_file, "rb") as f: - if b"get_network_ip" in f.read(): + file_content = f.read() + if b"get_network_ip" in file_content: injected_globals += "HOST_IP = '" + get_host_ip() + "'\n" + # Also include IPv6 host IP if we can determine it + try: + host_ipv6 = get_host_ipv6() + injected_globals += "HOST_IP6 = '" + host_ipv6 + "'\n" + except: + injected_globals += "HOST_IP6 = '::1'\n" # Default to localhost if cmd_args.trace_output: print("TRACE {}:".format("|".join(str(i) for i in instances))) 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