Page 1 of 1

Pico W: Problem binding a socket to a UDP Multicast Group

Posted: Wed Aug 24, 2022 11:38 am
by Beormund
I'm trying to get uPyEcho (Wemo emulator for Alexa discovery) to work on Pico W. I'm connected to wifi and MQTT using the async mqtt module. The following code is supposed to bind the socket to th UDP Multicast group ("239.255.255.250", 1900) which is what Alexa uses to discover Wemo devices. But I only receive broadcasts with a destination group ("255.255.255.255", 1900). I've checked my network using WireShark and Alexa is broadcasting discovery messages to 239.255.255.250. Any suggestions on how to resolve please?

Code: Select all

    def inet_aton(self, addr):
        ip_as_bytes = bytes(map(int, addr.split(".")))
        return ip_as_bytes

    async def init_socket(self):
        ok = True
        self.ip = "239.255.255.250"
        self.port = 1900
        try:
            # This is needed to join a multicast group
            self.mreq = struct.pack("4sl", self.inet_aton(self.ip), 0)
            # Set up server socket
            self.ssock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.ssock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            try:
                self.ssock.bind((self.ip, self.port)) # Also tried ("", self.port)
            except Exception as e:
                dbg("WARNING: Failed to bind %s:%d: %s", (self.ip, self.port, e))
                ok = False
            try:
                self.ssock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, self.mreq)
            except Exception as e:
                dbg("WARNING: Failed to join multicast group!: " + str(e))
                ok = False
        except Exception as e:
            dbg("Failed to initialize UPnP sockets!")
            return False
        if ok:
            dbg("Listening for UPnP broadcasts")

Re: Pico W: Problem binding a socket to a UDP Multicast Group

Posted: Wed Aug 24, 2022 12:44 pm
by Beormund
I suspect there is a bug preventing the socket joining a UDP multicast group

Code: Select all

# self.mreq = b'\xef\xff\xff\xfa\x00\x00\x00\x00'
self.ssock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, self.mreq)

Re: Pico W: Problem binding a socket to a UDP Multicast Group

Posted: Wed Aug 24, 2022 3:41 pm
by Beormund
Here's a stripped down test case for listening to UDP multicast broadcasts on 239.255.255.250:1900:

Code: Select all

# wlan access
SSID = '<ROUTER>'
WPA2_PASS = "<PASSWORD>"

ssid_ = SSID
wpa2_pass = WPA2_PASS

def do_connect():
    import network

    sta_if = network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print("connecting to network...")
        sta_if.active(True)
        sta_if.connect(ssid_, wpa2_pass)
        while not sta_if.isconnected():
            pass
    print("network config:", sta_if.ifconfig())

do_connect()

import socket
try:
    from socket import sockaddr
except:
    sockaddr = lambda x: x

def inet_aton(addr):
    ip_as_bytes = bytes(map(int, addr.split(".")))
    return ip_as_bytes

UPNP_MCAST_IP = "239.255.255.250"
UPNP_PORT = 1900
BIND_IP = "0.0.0.0"
REUSE_SOCKET = 0

serv_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = socket.getaddrinfo(BIND_IP, UPNP_PORT, socket.AF_INET, socket.SOCK_DGRAM)[0][4]
serv_sock.bind(addr)
serv_sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, inet_aton(UPNP_MCAST_IP) + inet_aton(BIND_IP));
if REUSE_SOCKET:
    resp_sock = serv_sock
else:
    resp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:
    data, addr = resp_sock.recvfrom(1024)
    if data.startswith(b"M-SEARCH"):
        print("From: ", sockaddr(addr))
        print(data)
This should publish quite a bit of udp broadcasting but doesn't on the pico w. If you have Alexa: "Alexa, discover devices..."
MicroPython firmware: rp2-pico-w-20220824-unstable-v1.19.1-316-g8139cbcf6.uf2

Re: Pico W: Problem binding a socket to a UDP Multicast Group

Posted: Thu Aug 25, 2022 2:03 pm
by jimmo
Beormund wrote:
Wed Aug 24, 2022 3:41 pm
Here's a stripped down test case for listening to UDP multicast broadcasts on 239.255.255.250:1900:
Thanks for the detailed info and repro!

I have a working example (running in CPython) than can pick up the SDDP multicasts on my network, but also unable to get this working on my Pico W.

It also works fine on an ESP32, so I think there's definitely a bug here. I have raised https://github.com/micropython/micropython/issues/9105 to track, please see updates there.

Re: Pico W: Problem binding a socket to a UDP Multicast Group

Posted: Fri Aug 26, 2022 2:06 pm
by jimmo
Beormund wrote:
Wed Aug 24, 2022 3:41 pm
Here's a stripped down test case for listening to UDP multicast broadcasts on 239.255.255.250:1900:
Thanks again for raising this. I've submitted a PR to fix the wifi driver.

Re: Pico W: Problem binding a socket to a UDP Multicast Group

Posted: Sun Aug 28, 2022 3:45 pm
by Beormund
Cheers jimmo

Re: Pico W: Problem binding a socket to a UDP Multicast Group

Posted: Tue Sep 20, 2022 9:11 am
by Beormund
jimmo wrote:
Fri Aug 26, 2022 2:06 pm
Beormund wrote:
Wed Aug 24, 2022 3:41 pm
Here's a stripped down test case for listening to UDP multicast broadcasts on 239.255.255.250:1900:
Thanks again for raising this. I've submitted a PR to fix the wifi driver.
The PR doesn't appear to have been approved upstream. Would it be possible to fork the driver, incorporate the fix locally and re-sync later?

Re: Pico W: Problem binding a socket to a UDP Multicast Group

Posted: Tue Sep 20, 2022 10:23 pm
by jimmo
Beormund wrote:
Tue Sep 20, 2022 9:11 am
The PR doesn't appear to have been approved upstream. Would it be possible to fork the driver, incorporate the fix locally and re-sync later?
Yes, absolutely.

No fork necessary, just fetch the PR into the lib/cyw43-driver submodule. (cd lib/cyw43-driver: git fetch origin pull/25/head:multicast-register; git checkout multicast-register)