Skip to content
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

Error: Failure to bind on ESP when using HTTPS with adafruit_httpserver #8947

Closed
michalpokusa opened this issue Feb 18, 2024 · 10 comments · Fixed by #8962
Closed

Error: Failure to bind on ESP when using HTTPS with adafruit_httpserver #8947

michalpokusa opened this issue Feb 18, 2024 · 10 comments · Fixed by #8962
Assignees
Labels
bug espressif applies to multiple Espressif chips network
Milestone

Comments

@michalpokusa
Copy link

CircuitPython version

Adafruit CircuitPython 9.0.0-beta.1 on 2024-02-17; Adafruit Feather ESP32-S2 TFT with ESP32S2
Adafruit CircuitPython 9.0.0-beta.1 on 2024-02-17; Adafruit MatrixPortal S3 with ESP32S3

Code/REPL

import ssl
import socketpool
import wifi

from adafruit_httpserver import Server, Request, Response


class TLSServerSocketPool:
    def __init__(self, pool, ssl_context):
        self._pool = pool
        self._ssl_context = ssl_context

    @property
    def AF_INET(self):
        return self._pool.AF_INET

    @property
    def SOCK_STREAM(self):
        return self._pool.SOCK_STREAM

    def socket(self, *args, **kwargs):
        socket = self._pool.socket(*args, **kwargs)

        # For CircuitPython 9.0.0-beta.1 and later
        socket.setsockopt(self._pool.SOL_SOCKET, self._pool.SO_REUSEADDR, 1)

        return self._ssl_context.wrap_socket(socket, server_side=True)

    def getaddrinfo(self, *args, **kwargs):
        return self._pool.getaddrinfo(*args, **kwargs)


pool = socketpool.SocketPool(wifi.radio)

ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(cadata="")
ssl_context.load_cert_chain("cert.pem", "key.pem")

tls_pool = TLSServerSocketPool(pool, ssl_context)

server = Server(tls_pool, "/static", debug=True)


@server.route("/")
def base(request: Request):
    """
    Serve a default static plain text message.
    """
    return Response(request, "Hello from the CircuitPython HTTPS Server!")


server.serve_forever(str(wifi.radio.ipv4_address), 8000)

Behavior

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Traceback (most recent call last):
  File "code.py", line 52, in <module>
  File "lib/adafruit_httpserver/server.py", line 186, in serve_forever
  File "lib/adafruit_httpserver/server.py", line 226, in start
ValueError: Error: Failure to bind

Code done running.

Description

No response

Additional information

While working on HTTPS support for adafruit_httpserver I noticed taht the latest version of CP changed something that seems to break code taht has been working until now regarding SSLSockets.

It used to work between e3c4b79e29ca691b972ccaad3576375e50ea08b1 and 9.0.0-beta.1, althought then I was getting MemoryError as described here

This is probably related to:
#8268
#8932

@jepler
Copy link
Member

jepler commented Feb 20, 2024

This code looks about the same as https://github.com/ide/circuitpython-https-server which I used (with modifications, see ide/circuitpython-https-server#2) when testing #8932

#8954 will not further increase compatibility with anything that uses socketpool sockets.

@jepler
Copy link
Member

jepler commented Feb 20, 2024

could be something wasn't quite right in #8940.

Can you test with these two specific uf2 files: https://adafruit-circuit-python.s3.amazonaws.com/bin/adafruit_matrixportal_s3/en_US/adafruit-circuitpython-adafruit_matrixportal_s3-en_US-20240217-main-PR8808-d0fec0c.uf2 and https://adafruit-circuit-python.s3.amazonaws.com/bin/adafruit_matrixportal_s3/en_US/adafruit-circuitpython-adafruit_matrixportal_s3-en_US-20240217-main-PR8940-6c1e34e.uf2 on the matrixportal? "PR8808" is from immediately before #8940 was merged, so if 8808 works and 8940 doesn't that helps narrow it down.

@anecdata
Copy link
Member

I was just bisecting when you posted @jepler ...

Adafruit CircuitPython 9.0.0-beta.0-51-gd0fec0c8b6 on 2024-02-17; Adafruit QT Py ESP32-S3 4MB Flash 2MB PSRAM with ESP32S3
works as HTTPS server,

Adafruit CircuitPython 9.0.0-beta.0-52-g6c1e34e957 on 2024-02-17; Adafruit QT Py ESP32-S3 4MB Flash 2MB PSRAM with ESP32S3 fails on server.start:

Traceback (most recent call last):
  File "code.py", line 56, in <module>
  File "adafruit_httpserver/server.py", line 226, in start
ValueError: Error: Failure to bind

@jepler
Copy link
Member

jepler commented Feb 20, 2024

@tannewt can you take a look? I didn't immediately spot how your change introduced this problem, maybe you'll see it though.

@anecdata
Copy link
Member

hmm, should the library only be calling

        self._sock.setsockopt(
            self._socket_source.SOL_SOCKET, self._socket_source.SO_REUSEADDR, 1
        )

when not CircuitPython?

        if implementation.name != "circuitpython":
            self._set_socket_level_to_reuse_address()

But calling it always yields:
AttributeError: 'SSLSocket' object has no attribute 'setsockopt'
so maybe the custom TLSServerSocketPool class needs extending?

@michalpokusa
Copy link
Author

michalpokusa commented Feb 20, 2024

@anecdata I believe you should set reuse before wraping socket with context.

#8947
In this issue I posted a all-in-one example with current adafruit_httpserver, before the compatibility with 9.0.0 PR that is still in progress.

@anecdata
Copy link
Member

Ah, thanks @michalpokusa that works, and it's back to ValueError: Error: Failure to bind

@michalpokusa
Copy link
Author

Ah, thanks @michalpokusa that works, and it's back to ValueError: Error: Failure to bind

Thanks for testing.

I just realized in previous response I linked to this exact issue 😅, happens when you jump between multiple issues/PRs. Nevertheless the class sets reuse before wraping.

@anecdata
Copy link
Member

(Adafruit CircuitPython 9.0.0-beta.0-52-g6c1e34e957 on 2024-02-17; Adafruit QT Py ESP32-S3 4MB Flash 2MB PSRAM with ESP32S3 works with non-SSL HTTP Server, so it does appear to be ssl-specific)

@tannewt tannewt added the espressif applies to multiple Espressif chips label Feb 20, 2024
@tannewt tannewt added this to the 9.0.0 milestone Feb 20, 2024
@tannewt tannewt self-assigned this Feb 20, 2024
@tannewt
Copy link
Member

tannewt commented Feb 20, 2024

@tannewt can you take a look? I didn't immediately spot how your change introduced this problem, maybe you'll see it though.

Yup. My brain went straight to "hey, I removed that error message". Looks like ssl socket is implicitly converting the new error number returned to a bool and then throwing the error message. Will fix today or tomorrow. It should be identical to the non-ssl socket change.

dhalbert pushed a commit that referenced this issue Feb 21, 2024
Non-ssl sockets now return size_t error numbers, not bool.

Fixes #8947
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug espressif applies to multiple Espressif chips network
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants