Skip to content

extmod/asyncio/stream.py: Add ipv6 support to start_server(). #17311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

andrewleech
Copy link
Contributor

Summary

I'm starting to use ipv6 more with micropython devices as their discoverability can actually be much better on a local network, without worrying about needing to manually configure (ipv4) ip addresses.

To that end, this PR adds support to start_server() to automatically use the parsed protocol, ie setting socket.AF_INET or socket.AF_INET6 on the socket as parsed by getaddrinfo()

When adding unit tests for this change, I found the multi-test runner was missing support for ipv6 ip address detection, so that's been added as well (in a separate commit)

The ip address detection in multi-test runner has also been updated to use the newer / preferred network.ipconfig("addr4") style interface by default, falling back to ipconfig if needed.

Testing

Unit tests are included which check ipv6 support in both net_hosted style test and mult_net tests.

Without the change to extmod/asyncio/stream.py the tests fails with OSError: 97

Trade-offs and Alternatives

Copy link

codecov bot commented May 16, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.54%. Comparing base (2dada06) to head (3b17ecc).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #17311   +/-   ##
=======================================
  Coverage   98.54%   98.54%           
=======================================
  Files         169      169           
  Lines       21898    21898           
=======================================
  Hits        21579    21579           
  Misses        319      319           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@andrewleech andrewleech force-pushed the asyncio_server_ipv6 branch from 3443947 to 56e8e68 Compare May 16, 2025 01:26
Copy link

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +4 +0.001% PYBV10
     mimxrt:    +0 +0.000% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:    +4 +0.001% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

@dpgeorge dpgeorge added the extmod Relates to extmod/ directory in source label May 20, 2025
@dpgeorge dpgeorge added this to the release-1.26.0 milestone May 20, 2025
@andrewleech andrewleech force-pushed the asyncio_server_ipv6 branch from 56e8e68 to 6227c48 Compare May 22, 2025 09:03
pi-anl added 2 commits May 27, 2025 14:53
Enhance network interface discovery in test framework:
- Add get_host_ipv6() function to determine host IPv6 address
- Update test template to include IPv6 address lookup
- Add helper method for IPv6 IP address retrieval from network interfaces
- Support modern interface address format (ifconfig with address type)

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
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>
@andrewleech andrewleech force-pushed the asyncio_server_ipv6 branch from 6227c48 to 3b17ecc Compare May 27, 2025 05:57
@@ -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!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be possible to add the family argument to start_server() and pass it through to getaddrinfo() here. Then you could force it to use IPv6 (or IPv4). But maybe that's a separate PR?


try:
# Check if IPv6 is supported
socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This detection won't work. All ports based on bare-metal lwIP will let this pass even if they don't have IPv6 enabled.

I don't know if it's possible to detect IPv6??

print("SKIP")
raise SystemExit

PORT = 8001 # Different from other tests to avoid conflicts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this needs to use a different port, 8000 should be fine.


async def handle_connection(reader, writer):
# Test that peername exists
peer = writer.get_extra_info("peername")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The peer variable is unused. I don't think you need to call this function at all.


data = await reader.read(100)
print("read:", data)
assert data == message, "Data mismatch"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need this assert, the .exp will test the data is correct.


try:
# Check if IPv6 is supported
socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, this detection won't work.

try:
# Connect with IPv6 client
print("connect to ipv6 server")
reader, writer = await asyncio.open_connection("::", PORT)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this to work requires loopback mode in the TCP/IP driver. That's fine on unix, but it'll fail on most bare-metal ports.

# Read response
data = await reader.read(100)
print("read:", data)
assert data == test_msg, "Data mismatch"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert not needed.

@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't add much, and I'm confused what "appropriate format" means?

pass

# Find active network interface
try:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code below is very hard to understand. Why so many try/except's?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extmod Relates to extmod/ directory in source
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
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