Exemple #1
0
def scan(timeout=DISCOVER_TIMEOUT):
    """Send a message over the network to discover uPnP devices.

    Inspired by Crimsdings
    https://github.com/crimsdings/ChromeCast/blob/master/cc_discovery.py

    Protocol explanation:
    https://embeddedinn.wordpress.com/tutorials/upnp-device-architecture/
    """
    ssdp_requests = ssdp_request(ST_ALL), ssdp_request(ST_ROOTDEVICE)

    stop_wait = datetime.now() + timedelta(seconds=timeout)

    sockets = []
    for addr in interface_addresses():
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

            # Set the time-to-live for messages for local network
            sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL,
                            SSDP_MX)
            sock.bind((addr, 0))
            sockets.append(sock)
        except socket.error:
            pass

    entries = {}
    for sock in [s for s in sockets]:
        try:
            for req in ssdp_requests:
                sock.sendto(req, SSDP_TARGET)
            sock.setblocking(False)
        except socket.error:
            sockets.remove(sock)
            sock.close()

    try:
        while sockets:
            time_diff = stop_wait - datetime.now()
            seconds_left = time_diff.total_seconds()
            if seconds_left <= 0:
                break

            ready = select.select(sockets, [], [], seconds_left)[0]

            for sock in ready:
                try:
                    response = sock.recv(1024).decode("utf-8")
                except socket.error:
                    logging.getLogger(__name__).exception(
                        "Socket error while discovering SSDP devices")
                    sockets.remove(sock)
                    sock.close()
                    continue

                entry = UPNPEntry.from_response(response)
                entries[(entry.st, entry.location)] = entry

    finally:
        for s in sockets:
            s.close()

    return sorted(entries.values(), key=lambda entry: entry.location)
Exemple #2
0
def scan(st=None, timeout=DISCOVER_TIMEOUT, max_entries=None):
    """Send a message over the network to discover uPnP devices.

    Inspired by Crimsdings
    https://github.com/crimsdings/ChromeCast/blob/master/cc_discovery.py

    Protocol explanation:
    https://embeddedinn.wordpress.com/tutorials/upnp-device-architecture/
    """
    # pylint: disable=too-many-nested-blocks,too-many-branches
    ssdp_st = st or ST_ALL
    ssdp_request = "\r\n".join([
        'M-SEARCH * HTTP/1.1',
        'HOST: 239.255.255.250:1900',
        'MAN: "ssdp:discover"',
        'MX: {:d}'.format(SSDP_MX),
        'ST: {}'.format(ssdp_st),
        '', '']).encode('utf-8')

    if st is None:
        # Wemo does not respond to a query for all devices+services
        # but only to a query for just root devices (ST_ROOTDEVICE). Use that
        # as well for the default case.
        alt_ssdp_request = "\r\n".join([
            'M-SEARCH * HTTP/1.1',
            'HOST: 239.255.255.250:1900',
            'MAN: "ssdp:discover"',
            'MX: {:d}'.format(SSDP_MX),
            'ST: {}'.format(ST_ROOTDEVICE),
            '', '']).encode('utf-8')

    stop_wait = datetime.now() + timedelta(0, timeout)

    sockets = []
    for addr in interface_addresses():
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

            # Set the time-to-live for messages for local network
            sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1)
            sock.bind((addr, 0))

            sockets.append(sock)
        except socket.error:
            pass

    entries = []
    for sock in [s for s in sockets]:
        try:
            sock.sendto(ssdp_request, SSDP_TARGET)
            if alt_ssdp_request:
                sock.sendto(alt_ssdp_request, SSDP_TARGET)
            sock.setblocking(False)
        except socket.error:
            sockets.remove(sock)
            sock.close()

    try:
        while sockets:
            time_diff = stop_wait - datetime.now()
            seconds_left = time_diff.total_seconds()
            if seconds_left <= 0:
                break

            ready = select.select(sockets, [], [], seconds_left)[0]

            for sock in ready:
                try:
                    response = sock.recv(1024).decode("utf-8")
                except socket.error:
                    logging.getLogger(__name__).exception(
                        "Socket error while discovering SSDP devices")
                    sockets.remove(sock)
                    sock.close()
                    continue

                entry = UPNPEntry.from_response(response)

                if (st is None or entry.st == st) and entry not in entries:
                    entries.append(entry)

                    if max_entries and len(entries) == max_entries:
                        raise StopIteration

    except StopIteration:
        pass

    finally:
        for s in sockets:
            s.close()

    return entries
Exemple #3
0
def scan(st=None, timeout=DISCOVER_TIMEOUT, max_entries=None):
    """
    Sends a message over the network to discover upnp devices.

    Inspired by Crimsdings
    https://github.com/crimsdings/ChromeCast/blob/master/cc_discovery.py

    Protocol explanation:
    https://embeddedinn.wordpress.com/tutorials/upnp-device-architecture/
    """
    # pylint: disable=too-many-nested-blocks,too-many-branches
    ssdp_st = st or ST_ALL
    ssdp_request = "\r\n".join([
        'M-SEARCH * HTTP/1.1',
        'HOST: 239.255.255.250:1900',
        'MAN: "ssdp:discover"',
        'MX: {:d}'.format(SSDP_MX),
        'ST: {}'.format(ssdp_st),
        '', '']).encode('utf-8')

    stop_wait = datetime.now() + timedelta(0, timeout)

    sockets = []
    for addr in interface_addresses():
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

            # Set the time-to-live for messages for local network
            sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1)
            sock.bind((addr, 0))

            sockets.append(sock)
        except socket.error:
            pass

    entries = []
    for sock in [s for s in sockets]:
        try:
            sock.sendto(ssdp_request, SSDP_TARGET)
            sock.setblocking(False)
        except socket.error:
            sockets.remove(sock)
            sock.close()

    try:
        while sockets:
            time_diff = stop_wait - datetime.now()
            seconds_left = time_diff.total_seconds()
            if seconds_left <= 0:
                break

            ready = select.select(sockets, [], [], seconds_left)[0]

            for sock in ready:
                try:
                    response = sock.recv(1024).decode("utf-8")
                except socket.error:
                    logging.getLogger(__name__).exception(
                        "Socket error while discovering SSDP devices")
                    sockets.remove(sock)
                    sock.close()
                    continue

                entry = UPNPEntry.from_response(response)

                if (st is None or entry.st == st) and entry not in entries:
                    entries.append(entry)

                    if max_entries and len(entries) == max_entries:
                        raise StopIteration

    except StopIteration:
        pass

    finally:
        for s in sockets:
            s.close()

    return entries