Пример #1
0
def test_backoff():
    got_query = Event()

    type_ = "_http._tcp.local."
    zeroconf_browser = Zeroconf(interfaces=['127.0.0.1'])

    # we are going to monkey patch the zeroconf send to check query transmission
    old_send = zeroconf_browser.send

    time_offset = 0.0
    start_time = time.time() * 1000
    initial_query_interval = r._BROWSER_TIME / 1000

    def current_time_millis():
        """Current system time in milliseconds"""
        return start_time + time_offset * 1000

    def send(out, addr=r._MDNS_ADDR, port=r._MDNS_PORT):
        """Sends an outgoing packet."""
        got_query.set()
        old_send(out, addr=addr, port=port)

    # monkey patch the zeroconf send
    setattr(zeroconf_browser, "send", send)

    # monkey patch the zeroconf current_time_millis
    r.current_time_millis = current_time_millis

    # monkey patch the backoff limit to prevent test running forever
    r._BROWSER_BACKOFF_LIMIT = 10  # seconds

    # dummy service callback
    def on_service_state_change(zeroconf, service_type, state_change, name):
        pass

    browser = ServiceBrowser(zeroconf_browser, type_,
                             [on_service_state_change])

    try:
        # Test that queries are sent at increasing intervals
        sleep_count = 0
        next_query_interval = 0.0
        expected_query_time = 0.0
        while True:
            zeroconf_browser.notify_all()
            sleep_count += 1
            got_query.wait(0.1)
            if time_offset == expected_query_time:
                assert got_query.is_set()
                got_query.clear()
                if next_query_interval == r._BROWSER_BACKOFF_LIMIT:
                    # Only need to test up to the point where we've seen a query
                    # after the backoff limit has been hit
                    break
                elif next_query_interval == 0:
                    next_query_interval = initial_query_interval
                    expected_query_time = initial_query_interval
                else:
                    next_query_interval = min(2 * next_query_interval,
                                              r._BROWSER_BACKOFF_LIMIT)
                    expected_query_time += next_query_interval
            else:
                assert not got_query.is_set()
            time_offset += initial_query_interval

    finally:
        browser.cancel()
        zeroconf_browser.close()
Пример #2
0
 def setUpClass(cls):
     cls.browser = Zeroconf(interfaces=['127.0.0.1'])
Пример #3
0
def setup(hass, config):
    """Set up Zeroconf and make AIS dom discoverable."""
    if not ais_global.has_root():
        return True
    from zeroconf import Zeroconf, ServiceInfo

    zero_config = Zeroconf()
    host_ip = util.get_local_ip()

    try:
        return_value = subprocess.check_output(
            "getprop net.hostname",
            timeout=15,
            shell=True,  # nosec
        )
        host_name = return_value.strip().decode("utf-8")
    except subprocess.CalledProcessError:
        host_name = socket.gethostname()
    if len(host_name) == 0:
        # get the mac address
        import uuid

        host_name = "".join([
            "{:02x}".format((uuid.getnode() >> i) & 0xFF)
            for i in range(0, 8 * 6, 8)
        ][::-1])
    if host_name.endswith(".local"):
        host_name = host_name[:-len(".local")]

    hass.states.async_set(
        "sensor.local_host_name",
        host_name.upper(),
        {
            "friendly_name": "Lokalna nazwa hosta",
            "icon": "mdi:dns"
        },
    )
    try:
        host_ip_pton = socket.inet_pton(socket.AF_INET, host_ip)
    except OSError:
        host_ip_pton = socket.inet_pton(socket.AF_INET6, host_ip)
    try:
        gate_id = ais_global.get_sercure_android_id_dom()
    except Exception:
        gate_id = "xxx"

    params = {
        "location_name": hass.config.location_name,
        "version": __version__,
        "company_url": "https://www.ai-speaker.com",
        "gate_id": gate_id,
    }

    # HTTP
    http_info = ServiceInfo(
        "_http._tcp.local.",
        name=host_name + "._http._tcp.local.",
        server=f"{host_name}.local.",
        addresses=[host_ip_pton],
        port=80,
        properties=params,
    )

    # FTP
    ftp_info = ServiceInfo(
        "_ftp._tcp.local.",
        name=host_name + "._ftp._tcp.local.",
        server=f"{host_name}.local.",
        addresses=[host_ip_pton],
        port=21,
        properties=params,
    )

    def zeroconf_hass_start(_event):
        """Expose Home Assistant on zeroconf when it starts.

        Wait till started or otherwise HTTP is not up and running.
        """
        _LOGGER.info("Starting Zeroconf broadcast")
        try:
            zero_config.register_service(http_info)
            zero_config.register_service(ftp_info)
        except NonUniqueNameException:
            _LOGGER.error(
                "Home Assistant instance with identical name present in the local network"
            )

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, zeroconf_hass_start)

    def stop_zeroconf(event):
        """Stop Zeroconf."""
        zero_config.unregister_service(http_info)
        zero_config.unregister_service(ftp_info)
        zero_config.close()

    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zeroconf)

    return True
Пример #4
0
    def __init__(self):
        super(MainWindow, self).__init__()
        self.showLogs = True
        available_out_ports = midiout.get_ports()
        self.midiin = rtmidi.MidiIn()
        available_in_ports = self.midiin.get_ports()

        # WIDGETS
        # top groupbox (utils)
        utilsGroupbox = QGroupBox("Utils")
        utilsWidgetContainer = QHBoxLayout()
        utilsGroupbox.setLayout(utilsWidgetContainer)

        # utils widgets
        btnRefreshMidiSources = QPushButton("Refresh available midi devices")
        btnRefreshMidiSources.clicked.connect(self.refreshMidiDevices)

        # create virtual midi ports btn
        btnCreateVirtualMidi = QPushButton("Create virtual ALSA midi ports")
        btnCreateVirtualMidi.clicked.connect(self.createAlsaVirtualMidiPorts)
        # remove virtual midi ports btn
        btnRemoveVirtualMidi = QPushButton("Remove virtual ALSA midi ports")
        btnRemoveVirtualMidi.clicked.connect(self.removeAlsaVirtualMidiPorts)

        utilsWidgetContainer.addWidget(btnRefreshMidiSources)
        utilsWidgetContainer.addWidget(btnCreateVirtualMidi)
        utilsWidgetContainer.addWidget(btnRemoveVirtualMidi)

        # MIDI SOURCES (BRIDGE-IN)
        midiInGroupbox = QGroupBox("Select midi bridge source")
        midiInGroupboxContainer = QHBoxLayout()
        midiInGroupbox.setLayout(midiInGroupboxContainer)

        self.comboIn = QComboBox()
        for min in available_in_ports:
            self.comboIn.addItem(min)
        self.comboIn.adjustSize()
        self.comboIn.activated[int].connect(self.selectMidiIn)

        midiInGroupboxContainer.addWidget(self.comboIn)
        midiInGroupbox.setLayout(midiInGroupboxContainer)

        # MIDI DEST (BRIDGE-OUT)
        midiOutGroupbox = QGroupBox("Select midi bridge destination")
        midiOutGroupboxContainer = QHBoxLayout()
        midiOutGroupbox.setLayout(midiOutGroupboxContainer)
        self.comboOut = QComboBox()
        for out in available_out_ports:
            self.comboOut.addItem(out)

        self.comboOut.adjustSize()
        self.comboOut.activated[int].connect(self.selectMidiOut)

        midiOutGroupboxContainer.addWidget(self.comboOut)
        midiOutGroupbox.setLayout(midiOutGroupboxContainer)

        # instanciate zeronconf
        zeroconf = Zeroconf()
        zero_listener = ZeroConfListener()

        # browse for _apple-midi._udp service
        browser = ServiceBrowser(zeroconf, "_apple-midi._udp.local.",
                                 zero_listener)

        grid = QGridLayout()
        grid.addWidget(utilsGroupbox, 0, 0)
        grid.addWidget(midiInGroupbox, 1, 0)
        grid.addWidget(midiOutGroupbox, 2, 0)

        widget = QWidget()
        widget.setLayout(grid)
        self.setCentralWidget(widget)
        self.setWindowTitle("RT-MIDI-BRIDGE UI")
        self.show()
Пример #5
0
        # self.Close(True)
        return 0


if __name__ == "__main__":

    HOST, PORT = socket.gethostbyname(socket.gethostname()), 9999

    app = App()
    vis = FeatherVisualization(None,
                               title=f"JoyWing @ {HOST} {PORT}",
                               size=(800, 600))
    vis.Show()

    #Prepare the broadcast of our service
    bonjour = Zeroconf()

    # Create the server, binding to localhost on port 9999
    with ThreadedUDPServer((HOST, PORT), FeatherUDPHandler) as server:

        server_thread = threading.Thread(target=server.serve_forever)
        # Exit the server thread when the main thread terminates
        server_thread.daemon = True
        server_thread.start()

        #Now that the server is reachable
        desc = {'version': '0.10'}
        addresses = [socket.inet_aton(HOST)]
        expected = {HOST}
        if socket.has_ipv6:
            addresses.append(socket.inet_pton(socket.AF_INET6, '::1'))
Пример #6
0
def test_known_answer_supression():
    zc = Zeroconf(interfaces=['127.0.0.1'])
    type_ = "_knownanswersv8._tcp.local."
    name = "knownname"
    registration_name = "%s.%s" % (name, type_)
    desc = {'path': '/~paulsm/'}
    server_name = "ash-2.local."
    info = ServiceInfo(
        type_, registration_name, 80, 0, 0, desc, server_name, addresses=[socket.inet_aton("10.0.1.2")]
    )
    zc.registry.add(info)

    now = current_time_millis()
    _clear_cache(zc)
    # Test PTR supression
    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(type_, const._TYPE_PTR, const._CLASS_IN)
    generated.add_question(question)
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    assert multicast_out is not None and multicast_out.answers

    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(type_, const._TYPE_PTR, const._CLASS_IN)
    generated.add_question(question)
    generated.add_answer_at_time(info.dns_pointer(), now)
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    # If the answer is suppressed, the additional should be suppresed as well
    assert not multicast_out or not multicast_out.answers

    # Test A supression
    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(server_name, const._TYPE_A, const._CLASS_IN)
    generated.add_question(question)
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    assert multicast_out is not None and multicast_out.answers

    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(server_name, const._TYPE_A, const._CLASS_IN)
    generated.add_question(question)
    for dns_address in info.dns_addresses():
        generated.add_answer_at_time(dns_address, now)
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    assert not multicast_out or not multicast_out.answers

    # Test SRV supression
    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(registration_name, const._TYPE_SRV, const._CLASS_IN)
    generated.add_question(question)
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    assert multicast_out is not None and multicast_out.answers

    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(registration_name, const._TYPE_SRV, const._CLASS_IN)
    generated.add_question(question)
    generated.add_answer_at_time(info.dns_service(), now)
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    # If the answer is suppressed, the additional should be suppresed as well
    assert not multicast_out or not multicast_out.answers

    # Test TXT supression
    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(registration_name, const._TYPE_TXT, const._CLASS_IN)
    generated.add_question(question)
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    assert multicast_out is not None and multicast_out.answers

    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(registration_name, const._TYPE_TXT, const._CLASS_IN)
    generated.add_question(question)
    generated.add_answer_at_time(info.dns_text(), now)
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    assert not multicast_out or not multicast_out.answers

    # unregister
    zc.registry.remove(info)
    zc.close()
Пример #7
0
def test_qu_response_only_sends_additionals_if_sends_answer():
    """Test that a QU response does not send additionals unless it sends the answer as well."""
    # instantiate a zeroconf instance
    zc = Zeroconf(interfaces=['127.0.0.1'])

    type_ = "_addtest1._tcp.local."
    name = "knownname"
    registration_name = "%s.%s" % (name, type_)
    desc = {'path': '/~paulsm/'}
    server_name = "ash-2.local."
    info = ServiceInfo(
        type_, registration_name, 80, 0, 0, desc, server_name, addresses=[socket.inet_aton("10.0.1.2")]
    )
    zc.registry.add(info)

    type_2 = "_addtest2._tcp.local."
    name = "knownname"
    registration_name2 = "%s.%s" % (name, type_2)
    desc = {'path': '/~paulsm/'}
    server_name2 = "ash-3.local."
    info2 = ServiceInfo(
        type_2, registration_name2, 80, 0, 0, desc, server_name2, addresses=[socket.inet_aton("10.0.1.2")]
    )
    zc.registry.add(info2)

    ptr_record = info.dns_pointer()

    # Add the PTR record to the cache
    zc.cache.add(ptr_record)

    # Add the A record to the cache with 50% ttl remaining
    a_record = info.dns_addresses()[0]
    a_record.set_created_ttl(current_time_millis() - (a_record.ttl * 1000 / 2), a_record.ttl)
    assert not a_record.is_recent(current_time_millis())
    zc.cache.add(a_record)

    # With QU should respond to only unicast when the answer has been recently multicast
    # even if the additional has not been recently multicast
    query = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN)
    question.unicast = True  # Set the QU bit
    assert question.unicast is True
    query.add_question(question)

    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in query.packets()], "1.2.3.4", const._MDNS_PORT
    )
    assert multicast_out is None
    assert a_record in unicast_out.additionals
    assert unicast_out.answers[0][0] == ptr_record

    # Remove the 50% A record and add a 100% A record
    zc.cache.remove(a_record)
    a_record = info.dns_addresses()[0]
    assert a_record.is_recent(current_time_millis())
    zc.cache.add(a_record)
    # With QU should respond to only unicast when the answer has been recently multicast
    # even if the additional has not been recently multicast
    query = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN)
    question.unicast = True  # Set the QU bit
    assert question.unicast is True
    query.add_question(question)

    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in query.packets()], "1.2.3.4", const._MDNS_PORT
    )
    assert multicast_out is None
    assert a_record in unicast_out.additionals
    assert unicast_out.answers[0][0] == ptr_record

    # Remove the 100% PTR record and add a 50% PTR record
    zc.cache.remove(ptr_record)
    ptr_record.set_created_ttl(current_time_millis() - (ptr_record.ttl * 1000 / 2), ptr_record.ttl)
    assert not ptr_record.is_recent(current_time_millis())
    zc.cache.add(ptr_record)
    # With QU should respond to only multicast since the has less
    # than 75% of its ttl remaining
    query = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN)
    question.unicast = True  # Set the QU bit
    assert question.unicast is True
    query.add_question(question)

    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in query.packets()], "1.2.3.4", const._MDNS_PORT
    )
    assert multicast_out.answers[0][0] == ptr_record
    assert a_record in multicast_out.additionals
    assert info.dns_text() in multicast_out.additionals
    assert info.dns_service() in multicast_out.additionals

    assert unicast_out is None

    # Ask 2 QU questions, with info the PTR is at 50%, with info2 the PTR is at 100%
    # We should get back a unicast reply for info2, but info should be multicasted since its within 75% of its TTL
    # With QU should respond to only multicast since the has less
    # than 75% of its ttl remaining
    query = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN)
    question.unicast = True  # Set the QU bit
    assert question.unicast is True
    query.add_question(question)

    question = r.DNSQuestion(info2.type, const._TYPE_PTR, const._CLASS_IN)
    question.unicast = True  # Set the QU bit
    assert question.unicast is True
    query.add_question(question)
    zc.cache.add(info2.dns_pointer())  # Add 100% TTL for info2 to the cache

    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in query.packets()], "1.2.3.4", const._MDNS_PORT
    )
    assert multicast_out.answers[0][0] == info.dns_pointer()
    assert info.dns_addresses()[0] in multicast_out.additionals
    assert info.dns_text() in multicast_out.additionals
    assert info.dns_service() in multicast_out.additionals

    assert unicast_out.answers[0][0] == info2.dns_pointer()
    assert info2.dns_addresses()[0] in unicast_out.additionals
    assert info2.dns_text() in unicast_out.additionals
    assert info2.dns_service() in unicast_out.additionals

    # unregister
    zc.registry.remove(info)
    zc.close()
Пример #8
0
async def test_async_with_sync_passed_in() -> None:
    """Test we can create and close the instance when passing in a sync Zeroconf."""
    zc = Zeroconf(interfaces=['127.0.0.1'])
    aiozc = AsyncZeroconf(zc=zc)
    assert aiozc.zeroconf is zc
    await aiozc.async_close()
Пример #9
0
import atexit
import ipaddress

from zeroconf import Zeroconf, ServiceInfo

ZCONF = Zeroconf()


class Provider(object):
    """
    Multi-cast DNS Service Provider

    Provide a multicast DNS service with the given name and type listening on the given
    port with additional information in the data record.

    :param name: Name of service
    :param service_type: Service Type string
    :param port: Service port

    Kwargs:
        - data: Additional data to make available to clients
        - unique: bool, only one permitted, collisoin if more than one
    """
    def __init__(self,
                 name,
                 service_type,
                 port,
                 data=None,
                 unique=False,
                 delay=1):
        super().__init__()
Пример #10
0
    def discover(self):
        print(
            "{status} Smart Module hosting asset {asset_id} {asset_type} {asset_context}."
            .format(status="Mock" if self.rtc.mock else "Real",
                    asset_id=self.asset.id,
                    asset_type=self.asset.type,
                    asset_context=self.asset.context))

        try:
            max_sleep_time = 3  # Calling sleep should be reviewed.
            zeroconf = Zeroconf()
            Log.info("Performing Broker discovery...")
            self.find_broker(zeroconf)
            time.sleep(max_sleep_time
                       )  # Wait for max_sleep_time to see if we found it.
            if self.comm.broker_name or self.comm.broker_ip:  # Found it.
                Log.info("MQTT Broker: {broker_name} IP: {broker_ip}.".format(
                    broker_name=self.comm.broker_name,
                    broker_ip=self.comm.broker_ip))
            else:  # Make necessary actions to become the broker.
                Log.info("Broker not found. Becoming the broker.")
                self.become_broker()
            time.sleep(max_sleep_time)
            self.comm.connect()  # Now it's time to connect to the broker.
        except Exception as excpt:
            Log.exception("[Exiting] Trying to find or become the broker.")
        finally:
            Log.info("Closing Zeroconf connection.")
            zeroconf.close()

        t_end = time.time() + 10
        while (time.time() < t_end) and not self.comm.is_connected:
            time.sleep(1)

        self.comm.subscribe("SCHEDULER/RESPONSE")
        self.comm.send("SCHEDULER/QUERY", "Where are you?")
        Log.info("Waiting for Scheduler response...")
        time.sleep(5)  # Just wait for reply... Need a review?

        self.comm.send("ANNOUNCE", self.hostname + " is online.")

        t_end = time.time() + 2
        while (time.time() < t_end) and not self.comm.is_connected:
            time.sleep(1)

        if not self.comm.scheduler_found:  # Become the Scheduler (necessary actions as Scheduler)
            try:
                Log.info("No Scheduler found. Becoming the Scheduler.")
                self.scheduler = Scheduler()
                self.scheduler.smart_module = self
                self.scheduler.prepare_jobs(self.scheduler.load_schedule())
                self.comm.scheduler_found = True
                self.comm.subscribe("SCHEDULER/QUERY")
                self.comm.unsubscribe("SCHEDULER/RESPONSE")
                self.comm.subscribe("STATUS/RESPONSE" + "/#")
                self.comm.subscribe("ASSET/RESPONSE" + "/#")
                self.comm.subscribe("ALERT" + "/#")
                self.comm.send("SCHEDULER/RESPONSE", self.hostname)
                self.comm.send("ANNOUNCE",
                               self.hostname + " is running the Scheduler.")
                Log.info("Scheduler program loaded.")
            except Exception as excpt:
                Log.exception("Error initializing scheduler. %s.", excpt)
Пример #11
0
 def __init__(self, callbackadd, callbackremove):
     self.zeroconf = Zeroconf()
     self.SERVICEBROWSER = None
     self.listener = self.LmrListener(callbackadd, callbackremove)
Пример #12
0
def test_tc_bit_defers_last_response_missing():
    zc = Zeroconf(interfaces=['127.0.0.1'])
    type_ = "_knowndefer._tcp.local."
    name = "knownname"
    name2 = "knownname2"
    name3 = "knownname3"

    registration_name = "%s.%s" % (name, type_)
    registration2_name = "%s.%s" % (name2, type_)
    registration3_name = "%s.%s" % (name3, type_)

    desc = {'path': '/~paulsm/'}
    server_name = "ash-2.local."
    server_name2 = "ash-3.local."
    server_name3 = "ash-4.local."

    info = r.ServiceInfo(type_,
                         registration_name,
                         80,
                         0,
                         0,
                         desc,
                         server_name,
                         addresses=[socket.inet_aton("10.0.1.2")])
    info2 = r.ServiceInfo(type_,
                          registration2_name,
                          80,
                          0,
                          0,
                          desc,
                          server_name2,
                          addresses=[socket.inet_aton("10.0.1.2")])
    info3 = r.ServiceInfo(type_,
                          registration3_name,
                          80,
                          0,
                          0,
                          desc,
                          server_name3,
                          addresses=[socket.inet_aton("10.0.1.2")])
    zc.registry.add(info)
    zc.registry.add(info2)
    zc.registry.add(info3)

    def threadsafe_query(*args):
        async def make_query():
            zc.handle_query(*args)

        asyncio.run_coroutine_threadsafe(make_query(), zc.loop).result()

    now = r.current_time_millis()
    _clear_cache(zc)
    source_ip = '203.0.113.12'

    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(type_, const._TYPE_PTR, const._CLASS_IN)
    generated.add_question(question)
    for _ in range(300):
        # Add so many answers we end up with another packet
        generated.add_answer_at_time(info.dns_pointer(), now)
    generated.add_answer_at_time(info2.dns_pointer(), now)
    generated.add_answer_at_time(info3.dns_pointer(), now)
    packets = generated.packets()
    assert len(packets) == 4
    expected_deferred = []

    next_packet = r.DNSIncoming(packets.pop(0))
    expected_deferred.append(next_packet)
    threadsafe_query(next_packet, source_ip, const._MDNS_PORT)
    assert zc._deferred[source_ip] == expected_deferred
    timer1 = zc._timers[source_ip]

    next_packet = r.DNSIncoming(packets.pop(0))
    expected_deferred.append(next_packet)
    threadsafe_query(next_packet, source_ip, const._MDNS_PORT)
    assert zc._deferred[source_ip] == expected_deferred
    timer2 = zc._timers[source_ip]
    if sys.version_info >= (3, 7):
        assert timer1.cancelled()
    assert timer2 != timer1

    # Send the same packet again to similar multi interfaces
    threadsafe_query(next_packet, source_ip, const._MDNS_PORT)
    assert zc._deferred[source_ip] == expected_deferred
    assert source_ip in zc._timers
    timer3 = zc._timers[source_ip]
    if sys.version_info >= (3, 7):
        assert not timer3.cancelled()
    assert timer3 == timer2

    next_packet = r.DNSIncoming(packets.pop(0))
    expected_deferred.append(next_packet)
    threadsafe_query(next_packet, source_ip, const._MDNS_PORT)
    assert zc._deferred[source_ip] == expected_deferred
    assert source_ip in zc._timers
    timer4 = zc._timers[source_ip]
    if sys.version_info >= (3, 7):
        assert timer3.cancelled()
    assert timer4 != timer3

    for _ in range(8):
        time.sleep(0.1)
        if source_ip not in zc._timers:
            break

    assert source_ip not in zc._deferred
    assert source_ip not in zc._timers

    # unregister
    zc.registry.remove(info)
    zc.close()
Пример #13
0
def test_get_service_info_failure_path():
    """Verify get_service_info return None when the underlying call returns False."""
    zc = Zeroconf(interfaces=['127.0.0.1'])
    assert zc.get_service_info("_neverused._tcp.local.",
                               "xneverused._neverused._tcp.local.", 10) is None
    zc.close()
Пример #14
0
def test_integration():
    service_added = Event()
    service_removed = Event()
    unexpected_ttl = Event()
    got_query = Event()

    type_ = "_http._tcp.local."
    registration_name = "xxxyyy.%s" % type_

    def on_service_state_change(zeroconf, service_type, state_change, name):
        if name == registration_name:
            if state_change is ServiceStateChange.Added:
                service_added.set()
            elif state_change is ServiceStateChange.Removed:
                service_removed.set()

    zeroconf_browser = Zeroconf(interfaces=['127.0.0.1'])

    # we are going to monkey patch the zeroconf send to check packet sizes
    old_send = zeroconf_browser.send

    time_offset = 0.0

    def current_time_millis():
        """Current system time in milliseconds"""
        return time.time() * 1000 + time_offset * 1000

    expected_ttl = r._DNS_HOST_TTL

    nbr_answers = 0

    def send(out, addr=r._MDNS_ADDR, port=r._MDNS_PORT):
        """Sends an outgoing packet."""
        pout = r.DNSIncoming(out.packet())
        nonlocal nbr_answers
        for answer in pout.answers:
            nbr_answers += 1
            if not answer.ttl > expected_ttl / 2:
                unexpected_ttl.set()

        got_query.set()
        old_send(out, addr=addr, port=port)

    # monkey patch the zeroconf send
    setattr(zeroconf_browser, "send", send)

    # monkey patch the zeroconf current_time_millis
    r.current_time_millis = current_time_millis

    # monkey patch the backoff limit to ensure we always get one query every 1/4 of the DNS TTL
    r._BROWSER_BACKOFF_LIMIT = int(expected_ttl / 4)

    service_added = Event()
    service_removed = Event()

    browser = ServiceBrowser(zeroconf_browser, type_,
                             [on_service_state_change])

    zeroconf_registrar = Zeroconf(interfaces=['127.0.0.1'])
    desc = {'path': '/~paulsm/'}
    info = ServiceInfo(type_, registration_name, socket.inet_aton("10.0.1.2"),
                       80, 0, 0, desc, "ash-2.local.")
    zeroconf_registrar.register_service(info)

    try:
        service_added.wait(1)
        assert service_added.is_set()

        # Test that we receive queries containing answers only if the remaining TTL
        # is greater than half the original TTL
        sleep_count = 0
        test_iterations = 50
        while nbr_answers < test_iterations:
            # Increase simulated time shift by 1/4 of the TTL in seconds
            time_offset += expected_ttl / 4
            zeroconf_browser.notify_all()
            sleep_count += 1
            got_query.wait(0.1)
            got_query.clear()
            # Prevent the test running indefinitely in an error condition
            assert sleep_count < test_iterations * 4
        assert not unexpected_ttl.is_set()

        # Don't remove service, allow close() to cleanup

    finally:
        zeroconf_registrar.close()
        service_removed.wait(1)
        assert service_removed.is_set()
        browser.cancel()
        zeroconf_browser.close()
Пример #15
0
    def test_ttl(self):

        # instantiate a zeroconf instance
        zc = Zeroconf(interfaces=['127.0.0.1'])

        # service definition
        type_ = "_test-srvc-type._tcp.local."
        name = "xxxyyy"
        registration_name = "%s.%s" % (name, type_)

        desc = {'path': '/~paulsm/'}
        info = ServiceInfo(
            type_,
            registration_name,
            80,
            0,
            0,
            desc,
            "ash-2.local.",
            addresses=[socket.inet_aton("10.0.1.2")],
        )

        nbr_answers = nbr_additionals = nbr_authorities = 0

        def get_ttl(record_type):
            if expected_ttl is not None:
                return expected_ttl
            elif record_type in [const._TYPE_A, const._TYPE_SRV]:
                return const._DNS_HOST_TTL
            else:
                return const._DNS_OTHER_TTL

        def _process_outgoing_packet(out):
            """Sends an outgoing packet."""
            nonlocal nbr_answers, nbr_additionals, nbr_authorities

            for answer, time_ in out.answers:
                nbr_answers += 1
                assert answer.ttl == get_ttl(answer.type)
            for answer in out.additionals:
                nbr_additionals += 1
                assert answer.ttl == get_ttl(answer.type)
            for answer in out.authorities:
                nbr_authorities += 1
                assert answer.ttl == get_ttl(answer.type)

        # register service with default TTL
        expected_ttl = None
        for _ in range(3):
            _process_outgoing_packet(zc.generate_service_query(info))
        zc.registry.add(info)
        for _ in range(3):
            _process_outgoing_packet(zc.generate_service_broadcast(info, None))
        assert nbr_answers == 12 and nbr_additionals == 0 and nbr_authorities == 3
        nbr_answers = nbr_additionals = nbr_authorities = 0

        # query
        query = r.DNSOutgoing(const._FLAGS_QR_QUERY | const._FLAGS_AA)
        assert query.is_query() is True
        query.add_question(r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN))
        query.add_question(r.DNSQuestion(info.name, const._TYPE_SRV, const._CLASS_IN))
        query.add_question(r.DNSQuestion(info.name, const._TYPE_TXT, const._CLASS_IN))
        query.add_question(r.DNSQuestion(info.server, const._TYPE_A, const._CLASS_IN))
        multicast_out = zc.query_handler.response(
            [r.DNSIncoming(packet) for packet in query.packets()], None, const._MDNS_PORT
        )[1]
        _process_outgoing_packet(multicast_out)

        # The additonals should all be suppresed since they are all in the answers section
        #
        assert nbr_answers == 4 and nbr_additionals == 0 and nbr_authorities == 0
        nbr_answers = nbr_additionals = nbr_authorities = 0

        # unregister
        expected_ttl = 0
        zc.registry.remove(info)
        for _ in range(3):
            _process_outgoing_packet(zc.generate_service_broadcast(info, 0))
        assert nbr_answers == 12 and nbr_additionals == 0 and nbr_authorities == 0
        nbr_answers = nbr_additionals = nbr_authorities = 0

        expected_ttl = None
        for _ in range(3):
            _process_outgoing_packet(zc.generate_service_query(info))
        zc.registry.add(info)
        # register service with custom TTL
        expected_ttl = const._DNS_HOST_TTL * 2
        assert expected_ttl != const._DNS_HOST_TTL
        for _ in range(3):
            _process_outgoing_packet(zc.generate_service_broadcast(info, expected_ttl))
        assert nbr_answers == 12 and nbr_additionals == 0 and nbr_authorities == 3
        nbr_answers = nbr_additionals = nbr_authorities = 0

        # query
        expected_ttl = None
        query = r.DNSOutgoing(const._FLAGS_QR_QUERY | const._FLAGS_AA)
        query.add_question(r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN))
        query.add_question(r.DNSQuestion(info.name, const._TYPE_SRV, const._CLASS_IN))
        query.add_question(r.DNSQuestion(info.name, const._TYPE_TXT, const._CLASS_IN))
        query.add_question(r.DNSQuestion(info.server, const._TYPE_A, const._CLASS_IN))
        _process_outgoing_packet(
            zc.query_handler.response(
                [r.DNSIncoming(packet) for packet in query.packets()], None, const._MDNS_PORT
            )[1]
        )
        assert nbr_answers == 4 and nbr_additionals == 0 and nbr_authorities == 0
        nbr_answers = nbr_additionals = nbr_authorities = 0

        # unregister
        expected_ttl = 0
        zc.registry.remove(info)
        for _ in range(3):
            _process_outgoing_packet(zc.generate_service_broadcast(info, 0))
        assert nbr_answers == 12 and nbr_additionals == 0 and nbr_authorities == 0
        nbr_answers = nbr_additionals = nbr_authorities = 0
        zc.close()
Пример #16
0
def setup(hass, config):
    """Set up Zeroconf and make Home Assistant discoverable."""
    zeroconf_name = '{}.{}'.format(hass.config.location_name, ZEROCONF_TYPE)

    params = {
        'version': __version__,
        'base_url': hass.config.api.base_url,
        # always needs authentication
        'requires_api_password': True,
    }

    host_ip = util.get_local_ip()

    try:
        host_ip_pton = socket.inet_pton(socket.AF_INET, host_ip)
    except socket.error:
        host_ip_pton = socket.inet_pton(socket.AF_INET6, host_ip)

    info = ServiceInfo(ZEROCONF_TYPE,
                       zeroconf_name,
                       None,
                       addresses=[host_ip_pton],
                       port=hass.http.server_port,
                       properties=params)

    zeroconf = Zeroconf()

    zeroconf.register_service(info)

    def service_update(zeroconf, service_type, name, state_change):
        """Service state changed."""
        if state_change != ServiceStateChange.Added:
            return

        service_info = zeroconf.get_service_info(service_type, name)
        info = info_from_service(service_info)
        _LOGGER.debug("Discovered new device %s %s", name, info)

        # If we can handle it as a HomeKit discovery, we do that here.
        if service_type == HOMEKIT_TYPE and handle_homekit(hass, info):
            return

        for domain in ZEROCONF[service_type]:
            hass.add_job(
                hass.config_entries.flow.async_init(domain,
                                                    context={'source': DOMAIN},
                                                    data=info))

    for service in ZEROCONF:
        ServiceBrowser(zeroconf, service, handlers=[service_update])

    if HOMEKIT_TYPE not in ZEROCONF:
        ServiceBrowser(zeroconf, HOMEKIT_TYPE, handlers=[service_update])

    def stop_zeroconf(_):
        """Stop Zeroconf."""
        zeroconf.unregister_service(info)
        zeroconf.close()

    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zeroconf)

    return True
Пример #17
0
def test_qu_response():
    """Handle multicast incoming with the QU bit set."""
    # instantiate a zeroconf instance
    zc = Zeroconf(interfaces=['127.0.0.1'])

    # service definition
    type_ = "_test-srvc-type._tcp.local."
    other_type_ = "_notthesame._tcp.local."
    name = "xxxyyy"
    registration_name = "%s.%s" % (name, type_)
    registration_name2 = "%s.%s" % (name, other_type_)
    desc = {'path': '/~paulsm/'}
    info = ServiceInfo(
        type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")]
    )
    info2 = ServiceInfo(
        other_type_,
        registration_name2,
        80,
        0,
        0,
        desc,
        "ash-other.local.",
        addresses=[socket.inet_aton("10.0.4.2")],
    )
    # register
    zc.register_service(info)

    def _validate_complete_response(query, out):
        assert out.id == query.id
        has_srv = has_txt = has_a = False
        nbr_additionals = 0
        nbr_answers = len(out.answers)
        nbr_authorities = len(out.authorities)
        for answer in out.additionals:
            nbr_additionals += 1
            if answer.type == const._TYPE_SRV:
                has_srv = True
            elif answer.type == const._TYPE_TXT:
                has_txt = True
            elif answer.type == const._TYPE_A:
                has_a = True
        assert nbr_answers == 1 and nbr_additionals == 3 and nbr_authorities == 0
        assert has_srv and has_txt and has_a

    # With QU should respond to only unicast when the answer has been recently multicast
    query = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN)
    question.unicast = True  # Set the QU bit
    assert question.unicast is True
    query.add_question(question)

    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in query.packets()], "1.2.3.4", const._MDNS_PORT
    )
    assert multicast_out is None
    _validate_complete_response(query, unicast_out)

    _clear_cache(zc)
    # With QU should respond to only multicast since the response hasn't been seen since 75% of the ttl
    query = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN)
    question.unicast = True  # Set the QU bit
    assert question.unicast is True
    query.add_question(question)
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in query.packets()], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    _validate_complete_response(query, multicast_out)

    # With QU set and an authorative answer (probe) should respond to both unitcast and multicast since the response hasn't been seen since 75% of the ttl
    query = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN)
    question.unicast = True  # Set the QU bit
    assert question.unicast is True
    query.add_question(question)
    query.add_authorative_answer(info2.dns_pointer())
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in query.packets()], "1.2.3.4", const._MDNS_PORT
    )
    _validate_complete_response(query, unicast_out)
    _validate_complete_response(query, multicast_out)

    _inject_response(zc, r.DNSIncoming(multicast_out.packets()[0]))
    # With the cache repopulated; should respond to only unicast when the answer has been recently multicast
    query = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(info.type, const._TYPE_PTR, const._CLASS_IN)
    question.unicast = True  # Set the QU bit
    assert question.unicast is True
    query.add_question(question)
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in query.packets()], "1.2.3.4", const._MDNS_PORT
    )
    assert multicast_out is None
    _validate_complete_response(query, unicast_out)
    # unregister
    zc.unregister_service(info)
    zc.close()
Пример #18
0
 def __init__(self, parent=None, **func_task):
     super(mDNS_BrowserThread, self).__init__(parent)
     self.ID_list = []
     self.zeroconf = Zeroconf()
     self.listener = MyListener()
Пример #19
0
def test_known_answer_supression_service_type_enumeration_query():
    zc = Zeroconf(interfaces=['127.0.0.1'])
    type_ = "_otherknown._tcp.local."
    name = "knownname"
    registration_name = "%s.%s" % (name, type_)
    desc = {'path': '/~paulsm/'}
    server_name = "ash-2.local."
    info = ServiceInfo(
        type_, registration_name, 80, 0, 0, desc, server_name, addresses=[socket.inet_aton("10.0.1.2")]
    )
    zc.registry.add(info)

    type_2 = "_otherknown2._tcp.local."
    name = "knownname"
    registration_name2 = "%s.%s" % (name, type_2)
    desc = {'path': '/~paulsm/'}
    server_name2 = "ash-3.local."
    info2 = ServiceInfo(
        type_2, registration_name2, 80, 0, 0, desc, server_name2, addresses=[socket.inet_aton("10.0.1.2")]
    )
    zc.registry.add(info2)
    now = current_time_millis()
    _clear_cache(zc)

    # Test PTR supression
    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(const._SERVICE_TYPE_ENUMERATION_NAME, const._TYPE_PTR, const._CLASS_IN)
    generated.add_question(question)
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    assert multicast_out is not None and multicast_out.answers

    generated = r.DNSOutgoing(const._FLAGS_QR_QUERY)
    question = r.DNSQuestion(const._SERVICE_TYPE_ENUMERATION_NAME, const._TYPE_PTR, const._CLASS_IN)
    generated.add_question(question)
    generated.add_answer_at_time(
        r.DNSPointer(
            const._SERVICE_TYPE_ENUMERATION_NAME,
            const._TYPE_PTR,
            const._CLASS_IN,
            const._DNS_OTHER_TTL,
            type_,
        ),
        now,
    )
    generated.add_answer_at_time(
        r.DNSPointer(
            const._SERVICE_TYPE_ENUMERATION_NAME,
            const._TYPE_PTR,
            const._CLASS_IN,
            const._DNS_OTHER_TTL,
            type_2,
        ),
        now,
    )
    packets = generated.packets()
    unicast_out, multicast_out = zc.query_handler.response(
        [r.DNSIncoming(packet) for packet in packets], "1.2.3.4", const._MDNS_PORT
    )
    assert unicast_out is None
    assert not multicast_out or not multicast_out.answers

    # unregister
    zc.registry.remove(info)
    zc.registry.remove(info2)
    zc.close()
Пример #20
0
 def start_zeroconf(self):
     self.zeroconf = Zeroconf()
     self.info = ServiceInfo("_http._tcp.local.", self.service_name,
                             socket.inet_aton(util.get_ip()),
                             prefs.get_port(), 0, 0, {}, "somehost.local.")
     self.zeroconf.register_service(self.info)
Пример #21
0
def PYRO_connector_factory(uri, confnodesroot):
    """
    This returns the connector to Pyro style PLCobject
    """
    confnodesroot.logger.write(_("PYRO connecting to URI : %s\n") % uri)

    servicetype, location = uri.split("://")
    if servicetype == "PYROS":
        schemename = "PYROLOCSSL"
        # Protect against name->IP substitution in Pyro3
        Pyro.config.PYRO_DNS_URI = True
        # Beware Pyro lib need str path, not unicode
        # don't rely on PYRO_STORAGE ! see documentation
        Pyro.config.PYROSSL_CERTDIR = os.path.abspath(
            str(confnodesroot.ProjectPath) + '/certs')
        if not os.path.exists(Pyro.config.PYROSSL_CERTDIR):
            confnodesroot.logger.write_error(
                'Error : the directory %s is missing for SSL certificates (certs_dir).'
                'Please fix it in your project.\n' %
                Pyro.config.PYROSSL_CERTDIR)
            return None
        else:
            confnodesroot.logger.write(
                _("PYRO using certificates in '%s' \n") %
                (Pyro.config.PYROSSL_CERTDIR))
        Pyro.config.PYROSSL_CERT = "client.crt"
        Pyro.config.PYROSSL_KEY = "client.key"

        # Ugly Monkey Patching
        def _gettimeout(self):
            return self.timeout

        def _settimeout(self, timeout):
            self.timeout = timeout

        from M2Crypto.SSL import Connection  # pylint: disable=import-error
        Connection.timeout = None
        Connection.gettimeout = _gettimeout
        Connection.settimeout = _settimeout
        # M2Crypto.SSL.Checker.WrongHost: Peer certificate commonName does not
        # match host, expected 127.0.0.1, got server
        Connection.clientPostConnectionCheck = None
    else:
        schemename = "PYROLOC"
    if location.find(service_type) != -1:
        try:
            from zeroconf import Zeroconf
            r = Zeroconf()
            i = r.get_service_info(service_type, location)
            if i is None:
                raise Exception("'%s' not found" % location)
            ip = str(socket.inet_ntoa(i.address))
            port = str(i.port)
            newlocation = ip + ':' + port
            confnodesroot.logger.write(
                _("'{a1}' is located at {a2}\n").format(a1=location,
                                                        a2=newlocation))
            location = newlocation
            r.close()
        except Exception:
            confnodesroot.logger.write_error(
                _("MDNS resolution failure for '%s'\n") % location)
            confnodesroot.logger.write_error(traceback.format_exc())
            return None

    # Try to get the proxy object
    try:
        RemotePLCObjectProxy = Pyro.core.getAttrProxyForURI(schemename +
                                                            "://" + location +
                                                            "/PLCObject")
    except Exception:
        confnodesroot.logger.write_error(
            _("Connection to '%s' failed.\n") % location)
        confnodesroot.logger.write_error(traceback.format_exc())
        return None

    def PyroCatcher(func, default=None):
        """
        A function that catch a Pyro exceptions, write error to logger
        and return default value when it happen
        """
        def catcher_func(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Pyro.errors.ConnectionClosedError, e:
                confnodesroot.logger.write_error(_("Connection lost!\n"))
                confnodesroot._SetConnector(None)
            except Pyro.errors.ProtocolError, e:
                confnodesroot.logger.write_error(_("Pyro exception: %s\n") % e)
            except Exception, e:
                # confnodesroot.logger.write_error(traceback.format_exc())
                errmess = ''.join(Pyro.util.getPyroTraceback(e))
                confnodesroot.logger.write_error(errmess + "\n")
                print(errmess)
                confnodesroot._SetConnector(None)
Пример #22
0
                    "username": "******",
                    "password": "******"
                }},
                upsert=True),
            UpdateOne({"username": "******"}, {
                "$setOnInsert": {
                    "username": "******",
                    "password": "******"
                }
            },
                      upsert=True),
            UpdateOne(
                {"username": "******"},
                {"$setOnInsert": {
                    "username": "******",
                    "password": "******"
                }},
                upsert=True)
        ]
        self.collection.bulk_write(operations)

    def getCollection(self):
        return self.collection


if __name__ == "__main__":
    authenticator = MyAuth()
    listener = MyListener()
    browser = ServiceBrowser(Zeroconf(), "_http._tcp.local.", listener)
    app.run(host='0.0.0.0', port=8080, debug=False)
Пример #23
0
 def __init__(self):
     self.zeroconf = Zeroconf()
     self.context = pyudev.Context()
     self.cpi = ConsolePi()
Пример #24
0
 def add_service(self, zeroconf, type, name):
   zeroconf = Zeroconf()
   listener = MyListener(cap)
   browser = ServiceBrowser(zeroconf, "_yulinmei._tcp.local.", listener)
Пример #25
0
    def test_lots_of_names(self):

        # instantiate a zeroconf instance
        zc = Zeroconf(interfaces=['127.0.0.1'])

        # create a bunch of servers
        type_ = "_my-service._tcp.local."
        name = 'a wonderful service'
        server_count = 300
        self.generate_many_hosts(zc, type_, name, server_count)

        # verify that name changing works
        self.verify_name_change(zc, type_, name, server_count)

        # we are going to monkey patch the zeroconf send to check packet sizes
        old_send = zc.send

        # needs to be a list so that we can modify it in our phony send
        longest_packet = [0, None]

        def send(out, addr=r._MDNS_ADDR, port=r._MDNS_PORT):
            """Sends an outgoing packet."""
            packet = out.packet()
            if longest_packet[0] < len(packet):
                longest_packet[0] = len(packet)
                longest_packet[1] = out
            old_send(out, addr=addr, port=port)

        # monkey patch the zeroconf send
        zc.send = send

        # dummy service callback
        def on_service_state_change(zeroconf, service_type, state_change,
                                    name):
            pass

        # start a browser
        browser = ServiceBrowser(zc, type_, [on_service_state_change])

        # wait until the browse request packet has maxed out in size
        sleep_count = 0
        while sleep_count < 100 and \
                longest_packet[0] < r._MAX_MSG_ABSOLUTE - 100:
            sleep_count += 1
            time.sleep(0.1)

        browser.cancel()
        time.sleep(0.5)

        import zeroconf
        zeroconf.log.debug('sleep_count %d, sized %d', sleep_count,
                           longest_packet[0])

        # now the browser has sent at least one request, verify the size
        assert longest_packet[0] <= r._MAX_MSG_ABSOLUTE
        assert longest_packet[0] >= r._MAX_MSG_ABSOLUTE - 100

        # mock zeroconf's logger warning() and debug()
        from mock import patch
        patch_warn = patch('zeroconf.log.warning')
        patch_debug = patch('zeroconf.log.debug')
        mocked_log_warn = patch_warn.start()
        mocked_log_debug = patch_debug.start()

        # now that we have a long packet in our possession, let's verify the
        # exception handling.
        out = longest_packet[1]
        out.data.append(b'\0' * 1000)

        # mock the zeroconf logger and check for the correct logging backoff
        call_counts = mocked_log_warn.call_count, mocked_log_debug.call_count
        # try to send an oversized packet
        zc.send(out)
        assert mocked_log_warn.call_count == call_counts[0] + 1
        assert mocked_log_debug.call_count == call_counts[0]
        zc.send(out)
        assert mocked_log_warn.call_count == call_counts[0] + 1
        assert mocked_log_debug.call_count == call_counts[0] + 1

        # force a receive of an oversized packet
        packet = out.packet()
        s = zc._respond_sockets[0]

        # mock the zeroconf logger and check for the correct logging backoff
        call_counts = mocked_log_warn.call_count, mocked_log_debug.call_count
        # force receive on oversized packet
        s.sendto(packet, 0, (r._MDNS_ADDR, r._MDNS_PORT))
        s.sendto(packet, 0, (r._MDNS_ADDR, r._MDNS_PORT))
        time.sleep(2.0)
        zeroconf.log.debug('warn %d debug %d was %s',
                           mocked_log_warn.call_count,
                           mocked_log_debug.call_count, call_counts)
        assert mocked_log_debug.call_count > call_counts[0]

        # close our zeroconf which will close the sockets
        zc.close()

        # pop the big chunk off the end of the data and send on a closed socket
        out.data.pop()
        zc._GLOBAL_DONE = False

        # mock the zeroconf logger and check for the correct logging backoff
        call_counts = mocked_log_warn.call_count, mocked_log_debug.call_count
        # send on a closed socket (force a socket error)
        zc.send(out)
        zeroconf.log.debug('warn %d debug %d was %s',
                           mocked_log_warn.call_count,
                           mocked_log_debug.call_count, call_counts)
        assert mocked_log_warn.call_count > call_counts[0]
        assert mocked_log_debug.call_count > call_counts[0]
        zc.send(out)
        zeroconf.log.debug('warn %d debug %d was %s',
                           mocked_log_warn.call_count,
                           mocked_log_debug.call_count, call_counts)
        assert mocked_log_debug.call_count > call_counts[0] + 2

        mocked_log_warn.stop()
        mocked_log_debug.stop()
Пример #26
0
	def init_search_for_cameras(self):
		self.zeroconf = Zeroconf()
		self.listener = CameraListener(self)
		self.browser = ServiceBrowser(self.zeroconf, "_http._tcp.local.", self.listener)
Пример #27
0
    def test_integration_with_listener_class(self):

        service_added = Event()
        service_removed = Event()

        subtype_name = "My special Subtype"
        type_ = "_http._tcp.local."
        subtype = subtype_name + "._sub." + type_
        name = "xxxyyy"
        registration_name = "%s.%s" % (name, type_)

        class MyListener(object):
            def add_service(self, zeroconf, type_, name):
                zeroconf.get_service_info(type, name)
                service_added.set()

            def remove_service(self, zeroconf, type_, name):
                service_removed.set()

        listener = MyListener()
        zeroconf_browser = Zeroconf(interfaces=['127.0.0.1'])
        zeroconf_browser.add_service_listener(subtype, listener)

        properties = dict(
            prop_none=None,
            prop_string=b'a_prop',
            prop_float=1.0,
            prop_blank=b'a blanked string',
            prop_true=1,
            prop_false=0,
        )

        zeroconf_registrar = Zeroconf(interfaces=['127.0.0.1'])
        desc = {'path': '/~paulsm/'}
        desc.update(properties)
        info_service = ServiceInfo(subtype, registration_name,
                                   socket.inet_aton("10.0.1.2"), 80, 0, 0,
                                   desc, "ash-2.local.")
        zeroconf_registrar.register_service(info_service)

        try:
            service_added.wait(1)
            assert service_added.is_set()

            # short pause to allow multicast timers to expire
            time.sleep(2)

            # clear the answer cache to force query
            for record in zeroconf_browser.cache.entries():
                zeroconf_browser.cache.remove(record)

            # get service info without answer cache
            info = zeroconf_browser.get_service_info(type_, registration_name)

            assert info.properties[b'prop_none'] is False
            assert info.properties[b'prop_string'] == properties['prop_string']
            assert info.properties[b'prop_float'] is False
            assert info.properties[b'prop_blank'] == properties['prop_blank']
            assert info.properties[b'prop_true'] is True
            assert info.properties[b'prop_false'] is False

            info = zeroconf_browser.get_service_info(subtype,
                                                     registration_name)
            assert info.properties[b'prop_none'] is False

            zeroconf_registrar.unregister_service(info_service)
            service_removed.wait(1)
            assert service_removed.is_set()
        finally:
            zeroconf_registrar.close()
            zeroconf_browser.remove_service_listener(listener)
            zeroconf_browser.close()
Пример #28
0
import socket
import sys

from zeroconf import __version__, ServiceInfo, Zeroconf

if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG)
    if len(sys.argv) > 1:
        assert sys.argv[1:] == ["--debug"]
        logging.getLogger("zeroconf").setLevel(logging.DEBUG)

    # Test a few module features, including service registration, service
    # query (for Zoe), and service unregistration.
    print("Multicast DNS Service Discovery for Python, version %s" %
          (__version__, ))
    r = Zeroconf()
    print("1. Testing registration of a service...")
    desc = {"version": "0.10", "a": "test value", "b": "another value"}
    info = ServiceInfo(
        "_http._tcp.local.",
        "My Service Name._http._tcp.local.",
        socket.inet_aton("127.0.0.1"),
        1234,
        0,
        0,
        desc,
    )
    print("   Registering service...")
    r.register_service(info)
    print("   Registration done.")
    print("2. Testing query of service information...")
Пример #29
0
address = None

# Sets global address when the service is found


class MyListener:
    def remove_service(self, zeroconf, type, name):
        pass

    def add_service(self, zeroconf, type, name):
        global address
        info = zeroconf.get_service_info(type, name)
        address = "{}:{}".format(socket.inet_ntoa(info.address), info.port)


zeroconf = Zeroconf()
listener = MyListener()
browser = ServiceBrowser(zeroconf, "{}.local.".format(SERVICE_TYPE), listener)

# Loop for 30s and wait for the service, if not found, exit
try:
    start = time.time()
    while time.time() - start < 30:
        if address is not None:
            break
        time.sleep(1)
finally:
    zeroconf.close()

if address is not None:
    print(address)
Пример #30
0
    def test_ttl(self):

        # instantiate a zeroconf instance
        zc = Zeroconf(interfaces=['127.0.0.1'])

        # service definition
        type_ = "_test-srvc-type._tcp.local."
        name = "xxxyyy"
        registration_name = "%s.%s" % (name, type_)

        desc = {'path': '/~paulsm/'}
        info = ServiceInfo(type_, registration_name,
                           socket.inet_aton("10.0.1.2"), 80, 0, 0, desc,
                           "ash-2.local.")

        # we are going to monkey patch the zeroconf send to check packet sizes
        old_send = zc.send

        nbr_answers = nbr_additionals = nbr_authorities = 0

        def get_ttl(record_type):
            if expected_ttl is not None:
                return expected_ttl
            elif record_type in [r._TYPE_A, r._TYPE_SRV]:
                return r._DNS_HOST_TTL
            else:
                return r._DNS_OTHER_TTL

        def send(out, addr=r._MDNS_ADDR, port=r._MDNS_PORT):
            """Sends an outgoing packet."""
            nonlocal nbr_answers, nbr_additionals, nbr_authorities

            for answer, time_ in out.answers:
                nbr_answers += 1
                assert answer.ttl == get_ttl(answer.type)
            for answer in out.additionals:
                nbr_additionals += 1
                assert answer.ttl == get_ttl(answer.type)
            for answer in out.authorities:
                nbr_authorities += 1
                assert answer.ttl == get_ttl(answer.type)
            old_send(out, addr=addr, port=port)

        # monkey patch the zeroconf send
        setattr(zc, "send", send)

        # register service with default TTL
        expected_ttl = None
        zc.register_service(info)
        assert nbr_answers == 12 and nbr_additionals == 0 and nbr_authorities == 3
        nbr_answers = nbr_additionals = nbr_authorities = 0

        # query
        query = r.DNSOutgoing(r._FLAGS_QR_QUERY | r._FLAGS_AA)
        query.add_question(r.DNSQuestion(info.type, r._TYPE_PTR, r._CLASS_IN))
        query.add_question(r.DNSQuestion(info.name, r._TYPE_SRV, r._CLASS_IN))
        query.add_question(r.DNSQuestion(info.name, r._TYPE_TXT, r._CLASS_IN))
        query.add_question(r.DNSQuestion(info.server, r._TYPE_A, r._CLASS_IN))
        zc.handle_query(r.DNSIncoming(query.packet()), r._MDNS_ADDR,
                        r._MDNS_PORT)
        assert nbr_answers == 4 and nbr_additionals == 4 and nbr_authorities == 0
        nbr_answers = nbr_additionals = nbr_authorities = 0

        # unregister
        expected_ttl = 0
        zc.unregister_service(info)
        assert nbr_answers == 12 and nbr_additionals == 0 and nbr_authorities == 0
        nbr_answers = nbr_additionals = nbr_authorities = 0

        # register service with custom TTL
        expected_ttl = r._DNS_HOST_TTL * 2
        assert expected_ttl != r._DNS_HOST_TTL
        zc.register_service(info, ttl=expected_ttl)
        assert nbr_answers == 12 and nbr_additionals == 0 and nbr_authorities == 3
        nbr_answers = nbr_additionals = nbr_authorities = 0

        # query
        query = r.DNSOutgoing(r._FLAGS_QR_QUERY | r._FLAGS_AA)
        query.add_question(r.DNSQuestion(info.type, r._TYPE_PTR, r._CLASS_IN))
        query.add_question(r.DNSQuestion(info.name, r._TYPE_SRV, r._CLASS_IN))
        query.add_question(r.DNSQuestion(info.name, r._TYPE_TXT, r._CLASS_IN))
        query.add_question(r.DNSQuestion(info.server, r._TYPE_A, r._CLASS_IN))
        zc.handle_query(r.DNSIncoming(query.packet()), r._MDNS_ADDR,
                        r._MDNS_PORT)
        assert nbr_answers == 4 and nbr_additionals == 4 and nbr_authorities == 0
        nbr_answers = nbr_additionals = nbr_authorities = 0

        # unregister
        expected_ttl = 0
        zc.unregister_service(info)
        assert nbr_answers == 12 and nbr_additionals == 0 and nbr_authorities == 0
        nbr_answers = nbr_additionals = nbr_authorities = 0