[Python] Python sockets SSDP search working inconsistently on Windows

Discussão em 'Python' iniciado por Stack, Dezembro 18, 2024.

  1. Stack

    Stack Membro Participativo

    Goal


    I am writing a python windows application that needs to search for available network devices using ssdp. The search will be used to get the IP addresses for specific device types to set up a connection.

    Problem


    We were getting very inconsistent ssdp search results. Sometimes it works, sometimes it fails. Using Wireshark and Device Sniffer (from Meshcommander UPnP tools), we discovered that when it fails, the ssdp M-SEARCH is getting sent to 127.0.0.1, so it never reaches the network. There appears to be no rhyme or reason for when it works or fails. I am confident this is specific to windows, as the same code works on Mac without issue.

    Code that works intermittently:

    import socket
    import struct
    import time

    local_ip = '192.168.20.48'
    ssdp_addr = "239.255.255.250"
    ssdp_port = 1900
    searchterm = 'ssdp:all'

    m_msg = f"""\
    M-SEARCH * HTTP/1.1\r\n\
    Host: {ssdp_addr}:{ssdp_port}\r\n\
    Man: "ssdp:discover"\r\n\
    ST: {searchterm}\r\n\
    MX: 2\r\n\r\n""".encode("utf-8")

    if __name__ == "__main__":
    # Method 1, occassionally works. Most of the time sends to 127.0.0.1:port
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 5)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    sock.settimeout(5)
    sock.sendto(m_msg, (ssdp_addr, ssdp_port)) # Sometimes works, sometimes doesn't...

    # If send worked, this will receive the response. But, if send is routed to 127.0.0.1,
    # nothing is received (which is expected given it is localhost)
    tLim = time.time() + 6
    while time.time() < tLim:
    try:
    data, addr = sock.recvfrom(4096)
    print(f"Received from {addr}: {data}")

    except socket.timeout:
    break

    sock.close()



    This issue also occurs with the ssdpy library on PyPi, which is not surprising as the source of the library is similar to the above implementation.

    Attempted Solution


    I have experimented with every type of windows configuration I can think of (Firewall settings, services, permissions, switching networks...) to no avail. After searching online I found a method where the sent M-Search message no longer gets routed to 127.0.0.1, but I am unable to receive the response from the device! With wireshark, I can see the response is sent by the device, but the code wont read it. Although the implementation WILL find the random ssdp traffic that is occurring at the same time on the network.

    import socket
    import struct
    import time

    local_ip = '192.168.20.48'
    ssdp_addr = "239.255.255.250"
    ssdp_port = 1900
    searchterm = 'ssdp:all'

    m_msg = f"""\
    M-SEARCH * HTTP/1.1\r\n\
    Host: {ssdp_addr}:{ssdp_port}\r\n\
    Man: "ssdp:discover"\r\n\
    ST: {searchterm}\r\n\
    MX: 2\r\n\r\n""".encode("utf-8")

    if __name__ == "__main__":
    # Method 2
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((local_ip, ssdp_port))

    group = socket.inet_aton(ssdp_addr)
    mreq = struct.pack('4s4s', group, socket.inet_aton(local_ip))
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
    sock.settimeout(5)

    ret = sock.sendto(m_msg, (ssdp_addr, ssdp_port))

    # CODE to listen for SSDP responses. This finds unrelated network upnp notifies, but
    # does not get the response from the device. I can see the response from the device is
    # being sent with wireshark
    tLim = time.time() + 6
    while time.time() < tLim:
    try:
    data, addr = sock.recvfrom(4096)
    print(f"Received from {addr}: {data}")

    except socket.timeout:
    break

    sock.close()


    With this method, Wireshark shows the M-SEARCH with Source/Destination = 192.168.20.48 / 239.255.255.250 and the response from the device Source/Destination = 192.168.30.82 / 192.168.20.48

    Where 192.168.20.48 = PC local IP, and 192.168.30.82 = device local IP.

    Help


    I am wondering if there are changes I can make to either of these methods to make them work consistently. The first method works part of the time, some of the time. The second method half works all the time. I am open to using a modified version of either of these methods, or a totally new one if I am completely on the wrong track.

    Continue reading...

Compartilhe esta Página