def discover_mqtt_host(): from zeroconf import ServiceBrowser, Zeroconf host = None info = None def on_service_state_change(zeroconf, service_type, name, state_change): pass zeroconf = Zeroconf() browser = ServiceBrowser(zeroconf, "_mqtt._tcp.local.", handlers=[on_service_state_change]) i = 0 while not host: time.sleep(0.1) if browser.services: service = list(browser.services.values())[0] info = zeroconf.get_service_info(service.name, service.alias) ##print('info', info) ##print('info.server', info.server) host = socket.inet_ntoa(info.address) i += 1 if i > 50: break zeroconf.close() try: return info.server, host except: pass return None
class Scanner(threading.Thread): def __init__(self): super(Scanner, self).__init__() self.abort = False def run(self): utils.Log('Starting Zeroconf Scan') self.listener = MyListener() self.zeroconf = Zeroconf() self.browser = ServiceBrowser(self.zeroconf, "_http._tcp.local.", self.listener) while not self.abort: xbmc.sleep(100) self.zeroconf.close() utils.Log('Ending Zeroconf Scan') exit() def stop(self): self.abort = True def getServers(self): return getServers()
def find_device_ip_and_port(device_id: str, max_seconds=10): """ Try to find a HomeKit Accessory via Bonjour. The process is time boxed by the second parameter which sets an upper limit of `max_seconds` before it times out. The runtime of the function may be longer because of the Bonjour handling code. :param device_id: the Accessory's pairing id :param max_seconds: the number of seconds to wait for the accessory to be found :return: a dict with ip and port if the accessory was found or None """ result = None zeroconf = Zeroconf() listener = CollectingListener() ServiceBrowser(zeroconf, '_hap._tcp.local.', listener) counter = 0 while result is None and counter < max_seconds: sleep(1) data = listener.get_data() for info in data: if info.properties[b'id'].decode() == device_id: result = {'ip': inet_ntoa(info.address), 'port': info.port} break counter += 1 zeroconf.close() return result
def main(): # Catch CNTRL-C signel global shutdown signal.signal(signal.SIGINT, signal_cntrl_c) init_logging("", 2) configs = load_configfile("bridge.ini") ignore_list = configs.getlist('Device', 'Ignore') context = zmq.Context.instance() zeroconf = Zeroconf() listener = ZeroConfDashTCPListener(context) browser = ServiceBrowser(zeroconf, "_DashIO._tcp.local.", listener) pinger = TCPPoller(port=5000, context=context) b = tcp_dashBridge( configs.get('Dash', 'Username'), configs.get('Dash', 'Password'), host=configs.get('Dash', 'Server'), port=configs.getint('Dash', 'Port'), ignore_devices=ignore_list, context=context ) while not shutdown: time.sleep(5) zeroconf.unregister_all_services() zeroconf.close()
def advertise(self): postfix = self.config['global']['service_prefix'] self.port = int(self.config['global']['port']) #print(self.config['device']['hostname']+postfix) info = ServiceInfo(postfix, self.config['device']['hostname']+"."+postfix, socket.inet_aton(self.ip), self.port, 0, 0, {'info': self.config['device']['description']}, "hazc.local.") self.bindConnection() zeroconf = Zeroconf() zeroconf.register_service(info) try: while True: # try: print("Ready") self.conn, self.addr = self.webcontrol.accept() self.listen() self.conn.close() except KeyboardInterrupt: pass finally: print() print("Unregistering...") zeroconf.unregister_service(info) zeroconf.close() try: print("Shutting down socket") self.webcontrol.shutdown(socket.SHUT_RDWR) except Exception as e: print(e)
def test_integration(): service_added = Event() service_removed = 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() browser = ServiceBrowser(zeroconf_browser, type_, [on_service_state_change]) zeroconf_registrar = Zeroconf() 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() # Don't remove service, allow close() to cleanup finally: zeroconf_registrar.close() browser.cancel() zeroconf_browser.close()
def test_integration_with_subtype_and_listener(self): subtype_ = "_subtype._sub" type_ = "_type._tcp.local." name = "xxxyyy" # Note: discovery returns only DNS-SD type not subtype discovery_type = "%s.%s" % (subtype_, type_) registration_name = "%s.%s" % (name, type_) zeroconf_registrar = Zeroconf(interfaces=['127.0.0.1']) desc = {'path': '/~paulsm/'} info = ServiceInfo( discovery_type, registration_name, socket.inet_aton("10.0.1.2"), 80, 0, 0, desc, "ash-2.local.") zeroconf_registrar.register_service(info) try: service_types = ZeroconfServiceTypes.find( interfaces=['127.0.0.1'], timeout=0.5) assert discovery_type in service_types service_types = ZeroconfServiceTypes.find( zc=zeroconf_registrar, timeout=0.5) assert discovery_type in service_types finally: zeroconf_registrar.close()
class RegisterCar(): def __init__(self): self.zeroconf = None self.info = None def register_car(self, name): my_ip_address = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1] # Link: https://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib if len(my_ip_address) > 0: logging.info("Service IP: " + my_ip_address[0]) my_ip_address = socket.inet_aton(my_ip_address[0]) desc = {'name': name} self.info = ServiceInfo("_http._tcp.local.", name + " DrivingMatter._http._tcp.local.", my_ip_address, 80, 0, 0, desc) self.zeroconf = Zeroconf() logging.info("Registration of a service, press Ctrl-C to exit...") self.zeroconf.register_service(self.info) return True else: logging.error("No network interface available, please connect to any network") #raise Exception("No network interface") return False def unregister_car(self): if self.zeroconf: self.zeroconf.unregister_service(self.info) self.zeroconf.close() logging.info("Service unregistered successfully") else: logging.error("No Zeroconf established yet")
class MDnsListener(object): """A MDNS Listener.""" def __init__(self): self.logger = _log.GetLogger('LogoCert') self.zeroconf = Zeroconf(InterfaceChoice.All) self.listener = MDnsService() def add_listener(self, proto): """Browse for announcements of a particular protocol. Args: proto: string, type of traffic to listen for. Returns: boolean, True = browser activated, False = errors detected. """ protocols = {'http': '_http._tcp.local.', 'ipp': '_ipp._tcp.local.', 'mdns': '_mdns._udp.local.', 'printer': '_printer._tcp.local.', 'privet': '_privet._tcp.local.', } if proto not in protocols: self.logger.error('Error starting listener, %s protocal unkown', proto) return False ServiceBrowser(self.zeroconf, protocols[proto], self.listener) self.logger.info('Browsing for %s services...', proto) return True def remove_listeners(self): """Remove all listeners.""" self.zeroconf.close() self.logger.info('All listeners have been stopped.')
def find_all_esses(): """ scan for all esses via mdns and return a list of mdns name strings. :return: """ from zeroconf import ServiceBrowser, Zeroconf esses = [] class MyListener: def remove_service(self, zeroconf, type, name): pass def add_service(self, zeroconf, type, name): info = zeroconf.get_service_info(type, name) esses.append(info.name) zeroconf = Zeroconf() listener = MyListener() # browser = ServiceBrowser(zeroconf, "_http._tcp.local.", listener) browser = ServiceBrowser(zeroconf, "_pmsctrl._tcp.local.", listener) time.sleep(3) zeroconf.close() if len(esses) == 0: raise ESSException("could not find any ESS devices via mdns") return esses
def test_01(self): """Node can discover network registration service via mDNS""" test = Test("Node can discover network registration service via mDNS") self.registry.reset() default_gw_interface = netifaces.gateways()['default'][ netifaces.AF_INET][1] default_ip = netifaces.ifaddresses(default_gw_interface)[ netifaces.AF_INET][0]['addr'] # TODO: Set api_ver to just the version under test. Later test support for parsing CSV string txt = {'api_ver': self.test_version, 'api_proto': 'http', 'pri': '0'} info = ServiceInfo("_nmos-registration._tcp.local.", "NMOS Test Suite._nmos-registration._tcp.local.", socket.inet_aton(default_ip), 5000, 0, 0, txt, "nmos-test.local.") zeroconf = Zeroconf() zeroconf.register_service(info) while ( time.time() - self.registry.last_time ) < 5: # Ensure we allow 5 seconds to get at least one heartbeat time.sleep(1) zeroconf.unregister_service(info) zeroconf.close() if len(self.registry.get_data()) > 0: return test.PASS() return test.FAIL( "Node did not attempt to register with the advertised registry.")
def test_12(self): """Node advertises a Node type mDNS announcement with no ver_* TXT records in the presence of a Registration API""" test = Test( "Node advertises a Node type mDNS announcement with no ver_* TXT records in the presence " "of a Registration API") zeroconf = Zeroconf() listener = MdnsListener() browser = ServiceBrowser(zeroconf, "_nmos-node._tcp.local.", listener) sleep(5) zeroconf.close() node_list = listener.get_service_list() for node in node_list: address = socket.inet_ntoa(node.address) port = node.port if address in self.node_url and ":{}".format( port) in self.node_url: properties_raw = node.properties for prop in properties_raw: if "ver_" in prop.decode('ascii'): return test.FAIL( "Found 'ver_'-txt record while node is registered." ) return test.PASS() return test.FAIL("No matching mdns announcement found for node.")
def main(): desc = '%s [Args] [Options]\nDetailed options -h or --help' % __file__ parser = ArgumentParser(description=desc) add_mqtt_arguments(parser, topic_default=DEFAULT_TOPIC_BASE) args = parser.parse_args() global topic_base topic_base = args.topic logging.basicConfig(level=get_log_level(args), format=LOG_FORMAT) zeroconf = Zeroconf() mqtt_client = mqtt.Client() listener = HostListener(mqtt_client) mqtt_client.on_connect = listener.on_connect mqtt_client.on_message = listener.on_message connect_mqtt(args, mqtt_client) browser = ServiceBrowser(zeroconf, SERVICE_TYPE, listener) try: mqtt_client.loop_forever() except KeyboardInterrupt: pass finally: zeroconf.close()
def discover_wifi(): queue: Queue[ServiceInfo] = Queue() conf = Zeroconf() def on_service_state_change(zeroconf: Zeroconf, service_type, name, state_change): if state_change == ServiceStateChange.Added: info = zeroconf.get_service_info(service_type, name) queue.put(info) try: ServiceBrowser(conf, BREWBLOX_DNS_TYPE, handlers=[on_service_state_change]) while True: info = queue.get(timeout=DISCOVER_TIMEOUT_S) if not info or not info.addresses or info.addresses == [ b'\x00\x00\x00\x00' ]: continue # discard simulators id = info.properties[b'ID'].decode() hw = info.properties[b'HW'].decode() host = inet_ntoa(info.addresses[0]) yield { 'connect': 'LAN', 'id': id, 'hw': hw, 'host': host, } except Empty: pass finally: conf.close()
def discover_wifi(): queue: Queue[ServiceInfo] = Queue() conf = Zeroconf() def on_service_state_change(zeroconf: Zeroconf, service_type, name, state_change): if state_change == ServiceStateChange.Added: info = zeroconf.get_service_info(service_type, name) queue.put(info) try: ServiceBrowser(conf, BREWBLOX_DNS_TYPE, handlers=[on_service_state_change]) while True: info = queue.get(timeout=DISCOVER_TIMEOUT_S) if not info or not info.addresses or info.addresses == [ b'\x00\x00\x00\x00' ]: continue # discard simulators id = info.server[:-len('.local.')] host = inet_ntoa(info.addresses[0]) port = info.port desc = f'LAN {id} {host} {port}' yield { 'id': id, 'desc': desc, 'host': host, 'port': port, } except Empty: pass finally: conf.close()
class EvaDiscoverer: def __init__(self, callback: DiscoverCallback, name: str = None): self.name = name self.callback = callback self.zeroconf = None def __enter__(self): self.zeroconf = Zeroconf() self.browser = ServiceBrowser(self.zeroconf, CHOREO_SERVICE, self) def __exit__(self, exc_type, exc_val, exc_tb): self.zeroconf.close() def __get_eva(self, zeroconf: Zeroconf, service_type: str, service_name: str): info = zeroconf.get_service_info(service_type, service_name) if info is None: return None return DiscoveredEva(host=info.server, name=info.properties[b'name'].decode("utf-8")) def __filter_name(self, eva): return self.name is not None and self.name != eva.name def add_service(self, zeroconf: Zeroconf, service_type: str, service_name: str): eva = self.__get_eva(zeroconf, service_type, service_name) if eva is None or self.__filter_name(eva): return self.callback('added', eva) def remove_service(self, zeroconf: Zeroconf, service_type: str, service_name: str): eva = self.__get_eva(zeroconf, service_type, service_name) if eva is None or self.__filter_name(eva): return self.callback('removed', eva)
def test_integration(): service_added = Event() service_removed = 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']) 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() # Don't remove service, allow close() to cleanup finally: zeroconf_registrar.close() browser.cancel() zeroconf_browser.close()
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)
def _fetch_fbx_mdns_info_via_mdns(self): print('Querying mDNS about Freebox Server information...') info = {} try: r = Zeroconf() serv_info = r.get_service_info( '_fbx-api._tcp.local.', 'Freebox Server._fbx-api._tcp.local.') info['api_domain'] = serv_info.properties[b'api_domain'].decode() info['https_available'] = True if serv_info.properties[ b'https_available'] == b'1' else False info['https_port'] = int(serv_info.properties[b'https_port']) info['api_base_url'] = serv_info.properties[ b'api_base_url'].decode() info['api_version'] = serv_info.properties[b'api_version'].decode() r.close() except Exception: print('Unable to retrieve configuration, assuming bridged mode') d = requests.get("http://mafreebox.freebox.fr/api_version") data = d.json() info['api_domain'] = data['api_domain'] info['https_available'] = data['https_available'] info['https_port'] = data['https_port'] info['api_base_url'] = data['api_base_url'] info['api_version'] = data['api_version'] return info
def discover(service_type: str, timeout: int = DEFAULT_TIMEOUT) -> List[ZeroconfDevice]: """Return all discovered zeroconf services of a given service type over given timeout period.""" services = [] def append_service(info: ServiceInfo) -> None: """Append discovered zeroconf service to service list.""" name = info.name[:-(len(info.type) + 1)] ip = info.parsed_addresses(IPVersion.V4Only)[0] port = info.port model = info.properties.get(b"name", "").decode("utf-8") id = info.properties.get(b"id") # handle id decode for various discovered use cases if isinstance(id, bytes): try: int(id, 16) except Exception: id = id.hex() else: id = None service = ZeroconfDevice(name, ip, port, model, id) services.append(service) zeroconf = Zeroconf() ServiceBrowser(zeroconf, service_type, ZeroconfListener(append_service)) time.sleep(timeout) zeroconf.close() return services
class Server: def __init__(self, name, address, port, description): self.zeroconf = Zeroconf() self.name = name self.description = description self.address = address self.port = port self.full_name = get_full_name(name) self.info = ServiceInfo(type_=TYPE, name=self.full_name, address=socket.inet_aton(self.address), port=self.port, weight=0, priority=0, properties=self.description) def register(self): logger.info("Broadcast server {} at {}:{}".format( self.full_name, self.address, self.port)) self.zeroconf.register_service(self.info) def unregister(self): self.zeroconf.unregister_service(self.info) def close(self): self.zeroconf.close()
class Browser: def __init__(self): self.zeroconf = Zeroconf() self.handlers = [] self.services = {} def list(self): return self.services.values() def get(self, name): return self.get_by_full_name(utils.get_full_name(name)) def get_by_full_name(self, full_name): return self.services.get(full_name) def wait(self, name, timeout=60): full_name = utils.get_full_name(name) event = Event() logger.info("Waiting the address and port info of {}".format(full_name)) def wait_handler(service): logger.info("Handle new service {}".format(Service)) if full_name == service.name: event.set() self.unregister_handler(wait_handler) self.register_handler(wait_handler) if full_name in self.services: logger.info("The service {} info is existing...".format(full_name)) event.set() self.unregister_handler(wait_handler) event.wait(timeout=timeout) return self.get_by_full_name(full_name) def handler(self, zeroconf, service_type, name, state_change): service = Service(zeroconf, service_type, name, state_change) if service.state == service.ADDED: logger.info("New service {} is added".format(name)) self.services[name] = service else: del self.services[name] for handler in self.handlers: handler(service) def register_handler(self, handler): self.handlers.append(handler) def unregister_handler(self, handler): self.handlers.remove(handler) def start(self): self.browser = ServiceBrowser(self.zeroconf, utils.TYPE, handlers=[self.handler]) def close(self): self.zeroconf.close()
def scan_for_apple_tvs(loop, timeout=5, abort_on_found=False, only_home_sharing=True): """Scan for Apple TVs using zeroconf (bonjour) and returns them.""" semaphore = asyncio.Semaphore(value=0, loop=loop) listener = _ServiceListener(abort_on_found, semaphore) zeroconf = Zeroconf() try: ServiceBrowser(zeroconf, HOMESHARING_SERVICE, listener) ServiceBrowser(zeroconf, DEVICE_SERVICE, listener) _LOGGER.debug('Discovering devices for %d seconds', timeout) yield from asyncio.wait_for(semaphore.acquire(), timeout, loop=loop) except concurrent.futures.TimeoutError: pass # Will happen when timeout occurs (totally normal) finally: zeroconf.close() def _should_include(atv): if not only_home_sharing: return True return atv.login_id is not None return list(filter(_should_include, listener.found_devices.values()))
def discover_remotes_mdns(do_thread=False): zeroconf = Zeroconf() try: properties = zeroconf.get_service_info(TYPE, NAME + '.' + TYPE).properties for _ in properties: print('{}: {}'.format(_, properties[_])) hostname = properties[b'hostname'].decode("utf-8") user = properties[b'user'].decode("utf-8") interfaces = json.loads(properties[b'interfaces'].decode("utf-8")) adapters = json.loads(properties[b'adapters'].decode("utf-8")) data = { hostname: { 'interfaces': interfaces, 'adapters': adapters, 'user': user } } print(data) if do_thread: threading.Thread(target=update_local_cloud_file, args=(LOCAL_CLOUD_FILE, data), name='avahi_local_cache_update').start() else: print('no thread') x = update_local_cloud_file(LOCAL_CLOUD_FILE, data) except AttributeError: pass finally: zeroconf.close()
def find(self, id, timeout=30): from zeroconf import ServiceBrowser, Zeroconf if not self.quiet: print("Discovering Digital Paper for {} seconds…".format(timeout)) sys.stdout.flush() self.id = id zc = Zeroconf() self.lock.acquire() ServiceBrowser(zc, ["_digitalpaper._tcp.local.", "_dp_fujitsu._tcp.local."], self) wait = self.lock.acquire(timeout=timeout) or (self.addr is not None) zc.close() if not wait: print("Failed".format(timeout)) return None else: if not self.quiet: print("Found digital paper at", self.addr) print("To skip the discovery process (and this message), call:") print() print( " {} --addr {} {}".format( sys.argv[0], self.addr, " ".join(sys.argv[1:]) ) ) print() return self.addr
class MdnsBrowser: def __init__(self, acteur): self.__logger = logging.getLogger(__name__ + '.' + self.__class__.__name__) self.zeroconf: Optional[Zeroconf] = None service_types = [ '_mghttps._tcp.local.', '_mgamqps._tcp.local.', ] self.listener = MdnsListener(acteur) # Activer zeroconf avec IPv4 et IPv6 (all) try: self.zeroconf = Zeroconf(ip_version=IPVersion.All) self.browser = ServiceBrowser(self.zeroconf, service_types, listener=self.listener) except OSError: self.__logger.warning( "Erreur chargement mdns avec IPv4 et IPv6, tenter de charger avec IPv4 uniquement" ) self.zeroconf = Zeroconf(ip_version=IPVersion.V4Only) self.browser = ServiceBrowser(self.zeroconf, service_types, listener=self.listener) def entretien(self): pass def fermer(self): self.zeroconf.unregister_all_services() self.zeroconf.close()
def resolve(type): zeroconf = Zeroconf() try: resolver = ServiceResolver(zeroconf) return resolver.resolve(type) finally: zeroconf.close()
def test_goodbye_all_services(): """Verify generating the goodbye query does not change with time.""" zc = Zeroconf(interfaces=['127.0.0.1']) out = zc.generate_unregister_all_services() assert out is None type_ = "_http._tcp.local." registration_name = "xxxyyy.%s" % type_ desc = {'path': '/~paulsm/'} info = r.ServiceInfo(type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")]) zc.registry.add(info) out = zc.generate_unregister_all_services() assert out is not None first_packet = out.packets() zc.registry.add(info) out2 = zc.generate_unregister_all_services() assert out2 is not None second_packet = out.packets() assert second_packet == first_packet # Verify the registery is empty out3 = zc.generate_unregister_all_services() assert out3 is None assert zc.registry.get_service_infos() == [] zc.close()
def test_invalid_packets_ignored_and_does_not_cause_loop_exception(): """Ensure an invalid packet cannot cause the loop to collapse.""" zc = Zeroconf(interfaces=['127.0.0.1']) generated = r.DNSOutgoing(0) packet = generated.packets()[0] packet = packet[:8] + b'deadbeef' + packet[8:] parsed = r.DNSIncoming(packet) assert parsed.valid is False mock_out = unittest.mock.Mock() mock_out.packets = lambda: [packet] zc.send(mock_out) generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE) entry = r.DNSText( "didnotcrashincoming._crash._tcp.local.", const._TYPE_TXT, const._CLASS_IN | const._CLASS_UNIQUE, 500, b'path=/~paulsm/', ) assert isinstance(entry, r.DNSText) assert isinstance(entry, r.DNSRecord) assert isinstance(entry, r.DNSEntry) generated.add_answer_at_time(entry, 0) zc.send(generated) time.sleep(0.2) zc.close() assert zc.cache.get(entry) is not None
def find(cls, timeout=10, fast=False): """Use Zeroconf/Bonjour to locate AirPlay servers on the local network Args: timeout(int): The number of seconds to wait for responses. If fast is false, then this function will always block for this number of seconds. fast(bool): If true, do not wait for timeout to expire, return as soon as we've found at least one AirPlay server Returns: list: A list of AirPlay() objects; one for each AirPlay server found """ # this will be our list of devices devices = [] # zeroconf will call this method when a device is found def on_service_state_change(zeroconf, service_type, name, state_change): if state_change is ServiceStateChange.Added: info = zeroconf.get_service_info(service_type, name) if info is None: return try: name, _ = name.split('.', 1) except ValueError: pass devices.append( cls(socket.inet_ntoa(info.address), info.port, name) ) # search for AirPlay devices try: zeroconf = Zeroconf() browser = ServiceBrowser(zeroconf, "_airplay._tcp.local.", handlers=[on_service_state_change]) # NOQA except NameError: warnings.warn( 'AirPlay.find() requires the zeroconf package but it could not be imported. ' 'Install it if you wish to use this method. https://pypi.python.org/pypi/zeroconf', stacklevel=2 ) return None # enforce the timeout timeout = time.time() + timeout try: while time.time() < timeout: # if they asked us to be quick, bounce as soon as we have one AirPlay if fast and len(devices): break time.sleep(0.05) except KeyboardInterrupt: # pragma: no cover pass finally: zeroconf.close() return devices
def test_legacy_record_update_listener(): """Test a RecordUpdateListener that does not implement update_records.""" # instantiate a zeroconf instance zc = Zeroconf(interfaces=['127.0.0.1']) with pytest.raises(RuntimeError): r.RecordUpdateListener().update_record( zc, 0, r.DNSRecord('irrelevant', const._TYPE_SRV, const._CLASS_IN, const._DNS_HOST_TTL) ) updates = [] class LegacyRecordUpdateListener(r.RecordUpdateListener): """A RecordUpdateListener that does not implement update_records.""" def update_record(self, zc: 'Zeroconf', now: float, record: r.DNSRecord) -> None: nonlocal updates updates.append(record) listener = LegacyRecordUpdateListener() zc.add_listener(listener, None) # dummy service callback def on_service_state_change(zeroconf, service_type, state_change, name): pass # start a browser type_ = "_homeassistant._tcp.local." name = "MyTestHome" browser = ServiceBrowser(zc, type_, [on_service_state_change]) info_service = ServiceInfo( type_, '%s.%s' % (name, type_), 80, 0, 0, {'path': '/~paulsm/'}, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")], ) zc.register_service(info_service) zc.wait(1) browser.cancel() assert len(updates) assert len([isinstance(update, r.DNSPointer) and update.name == type_ for update in updates]) >= 1 zc.remove_listener(listener) # Removing a second time should not throw zc.remove_listener(listener) zc.close()
def find(cls, timeout=10, fast=False): """Use Zeroconf/Bonjour to locate AirPlay servers on the local network Args: timeout(int): The number of seconds to wait for responses. If fast is false, then this function will always block for this number of seconds. fast(bool): If true, do not wait for timeout to expire, return as soon as we've found at least one AirPlay server Returns: list: A list of AirPlay() objects; one for each AirPlay server found """ # this will be our list of devices devices = [] # zeroconf will call this method when a device is found def on_service_state_change(zeroconf, service_type, name, state_change): if state_change is ServiceStateChange.Added: info = zeroconf.get_service_info(service_type, name) if info is None: return try: name, _ = name.split('.', 1) except ValueError: pass devices.append( cls(socket.inet_ntoa(info.address), info.port, name) ) # search for AirPlay devices try: zeroconf = Zeroconf() browser = ServiceBrowser(zeroconf, "_airplay._tcp.local.", handlers=[on_service_state_change]) # NOQA except NameError: warnings.warn( 'AirPlay.find() requires the zeroconf package but it could not be imported. ' 'Install it if you wish to use this method. https://pypi.python.org/pypi/zeroconf', stacklevel=2 ) return None # enforce the timeout timeout = time.time() + timeout try: while time.time() < timeout: # if they asked us to be quick, bounce as soon as we have one AirPlay if fast and len(devices): break time.sleep(0.05) except Exception: # pragma: no cover pass zeroconf.close() return devices
def scan_su(): open('SUs', 'w').close() zeroconf = Zeroconf() browser = ServiceBrowser(zeroconf, "_su._tcp.local.", handlers=[on_service_state_change]) sleep(1) zeroconf.close()
def discover(service: str = "_axis-video._tcp.local."): """Discover local services""" zeroconf = Zeroconf() listener = Listener() browser = ServiceBrowser(zeroconf, service, listener) try: input("Press enter to exit...") finally: zeroconf.close()
def cmd_servers(self): zeroconf = Zeroconf() listener = ZeroConfListener() ServiceBrowser(zeroconf, ZEROCONF_TYPE, listener) print("Looking for devices") time.sleep(5) zeroconf.close() for name, info in listener.devices.items(): print("{}: {}".format(name, info))
class GlancesAutoDiscoverClient(object): """Implementation of the zeroconf protocol (client side for the Glances server).""" def __init__(self, hostname, args=None): if zeroconf_tag: zeroconf_bind_address = args.bind_address try: self.zeroconf = Zeroconf() except socket.error as e: logger.error("Cannot start zeroconf: {}".format(e)) # XXX *BSDs: Segmentation fault (core dumped) # -- https://bitbucket.org/al45tair/netifaces/issues/15 if not BSD: try: # -B @ overwrite the dynamic IPv4 choice if zeroconf_bind_address == '0.0.0.0': zeroconf_bind_address = self.find_active_ip_address() except KeyError: # Issue #528 (no network interface available) pass self.info = ServiceInfo( zeroconf_type, '{}:{}.{}'.format(hostname, args.port, zeroconf_type), address=socket.inet_aton(zeroconf_bind_address), port=args.port, weight=0, priority=0, properties={}, server=hostname) try: self.zeroconf.register_service(self.info) except socket.error as e: logger.error( "Error while announcing Glances server: {}".format(e)) else: print( "Announce the Glances server on the LAN (using {} IP address)" .format(zeroconf_bind_address)) else: logger.error( "Cannot announce Glances server on the network: zeroconf library not found." ) @staticmethod def find_active_ip_address(): """Try to find the active IP addresses.""" import netifaces # Interface of the default gateway gateway_itf = netifaces.gateways()['default'][netifaces.AF_INET][1] # IP address for the interface return netifaces.ifaddresses(gateway_itf)[netifaces.AF_INET][0]['addr'] def close(self): if zeroconf_tag: self.zeroconf.unregister_service(self.info) self.zeroconf.close()
def main(): """Main entry point.""" main = MainApplication() zeroconf = Zeroconf() listener = MyListener(main.get_control()) browser = ServiceBrowser(zeroconf, "_http._tcp.local.", listener) try: main.mainloop() finally: zeroconf.close()
def get_others(self): """ Wait for other services to make themselves visible """ zeroconf = Zeroconf() _ = ServiceBrowser(zeroconf, "_http._tcp.local.", handlers=[self.on_service_state_change]) for _ in range(1, 10 + 1): time.sleep(1) zeroconf.close() return self.known_servers
def test_close_waits_for_threads(): class Dummy(object): def add_service(self, zeroconf_obj, service_type, name): pass def remove_service(self, zeroconf_obj, service_type, name): pass z = Zeroconf() z.add_service_listener('_privet._tcp.local.', listener=Dummy()) z.close() assert not z.browsers[0].is_alive()
class GlancesAutoDiscoverClient(object): """Implementation of the zeroconf protocol (client side for the Glances server).""" def __init__(self, hostname, args=None): if zeroconf_tag: zeroconf_bind_address = args.bind_address try: self.zeroconf = Zeroconf() except socket.error as e: logger.error("Cannot start zeroconf: {}".format(e)) # XXX *BSDs: Segmentation fault (core dumped) # -- https://bitbucket.org/al45tair/netifaces/issues/15 if not BSD: try: # -B @ overwrite the dynamic IPv4 choice if zeroconf_bind_address == '0.0.0.0': zeroconf_bind_address = self.find_active_ip_address() except KeyError: # Issue #528 (no network interface available) pass # Check IP v4/v6 address_family = socket.getaddrinfo(zeroconf_bind_address, args.port)[0][0] # Start the zeroconf service self.info = ServiceInfo( zeroconf_type, '{}:{}.{}'.format(hostname, args.port, zeroconf_type), address=socket.inet_pton(address_family, zeroconf_bind_address), port=args.port, weight=0, priority=0, properties={}, server=hostname) try: self.zeroconf.register_service(self.info) except socket.error as e: logger.error("Error while announcing Glances server: {}".format(e)) else: print("Announce the Glances server on the LAN (using {} IP address)".format(zeroconf_bind_address)) else: logger.error("Cannot announce Glances server on the network: zeroconf library not found.") @staticmethod def find_active_ip_address(): """Try to find the active IP addresses.""" import netifaces # Interface of the default gateway gateway_itf = netifaces.gateways()['default'][netifaces.AF_INET][1] # IP address for the interface return netifaces.ifaddresses(gateway_itf)[netifaces.AF_INET][0]['addr'] def close(self): if zeroconf_tag: self.zeroconf.unregister_service(self.info) self.zeroconf.close()
def run(self): #Log.debug('get_service_info') zeroconf = Zeroconf() listener = ServiceListener() service_type = "_compass_discovery._tcp.local." browser = ServiceBrowser(zeroconf, service_type, listener) #Log.debug('enter browser') try: while True: pass finally: zeroconf.close()
def serviceStatus(): zeroconf = Zeroconf() info = zeroconf.get_service_info("_http._tcp.local.", "Takiyaki._http._tcp.local.") # If service registered # if info: return (socket.inet_ntoa(info.address), info.port) # No named service registered # else: print("Service doesn't exist") zeroconf.close()
def from_dacp_id(cls, dacp_id, token): zeroconf = Zeroconf() try: listener = ServiceListener(airplay_prefix.format(dacp_id=dacp_id), zeroconf) browser = ServiceBrowser(zeroconf, airplay_zeroconf_service, listener) wait_for_it = ResultWaiter(listener, browser) wait_for_it.start() wait_for_it.join() del wait_for_it finally: zeroconf.close() assert(listener.info) # fails if service was not found. host = "http://" + binary_ip_to_str(listener.info.address) port = listener.info.port return AirplayRemote(token, host, port)
class ServerPublisher: def __init__(self): self.zero_conf = Zeroconf() def publish(self, host, port): log.debug('publishing server at %s:%s' % (host, port)) hostname = gethostname() service_info = ServiceInfo("_checkers._tcp.local.", "%s._checkers._tcp.local." % hostname, inet_aton(host), port, 0, 0, {}, server=hostname + '.local') self.zero_conf.registerService(service_info) def shutdown(self): log.debug('shutting down server publisher') self.zero_conf.unregisterAllServices() self.zero_conf.close()
def createService(): zeroconf = Zeroconf() # Look up info's __init__ in python-zeroconf's documentation # info = ServiceInfo("_http._tcp.local.", "Takiyaki._http._tcp.local.", socket.inet_aton(socket.gethostbyname(socket.gethostname())), 8080,0,0,socket.gethostname() + ".local.") # Server is supported but not compulsory, set server as inputted name # print "Registered Service [" + info.name + "]" zeroconf.register_service(info) try: while True: sleep(0.1) except KeyboardInterrupt: zeroconf.unregister_service(info) print("Unregistered") zeroconf.close() print("Service registered") zeroconf.close()
class GlancesAutoDiscoverClient(object): """Implementation of the zeroconf protocol (client side for the Glances server).""" def __init__(self, hostname, args=None): if zeroconf_tag: zeroconf_bind_address = args.bind_address try: self.zeroconf = Zeroconf() except socket.error as e: logger.error("Cannot start zeroconf: {0}".format(e)) try: # -B @ overwrite the dynamic IPv4 choice if zeroconf_bind_address == '0.0.0.0': zeroconf_bind_address = self.find_active_ip_address() except KeyError: # Issue #528 (no network interface available) pass print("Announce the Glances server on the LAN (using {0} IP address)".format(zeroconf_bind_address)) self.info = ServiceInfo( zeroconf_type, '{0}:{1}.{2}'.format(hostname, args.port, zeroconf_type), address=socket.inet_aton(zeroconf_bind_address), port=args.port, weight=0, priority=0, properties={}, server=hostname) self.zeroconf.register_service(self.info) else: logger.error("Cannot announce Glances server on the network: zeroconf library not found.") @staticmethod def find_active_ip_address(): """Try to find the active IP addresses.""" if not 'freebsd' in sys.platform: import netifaces # Interface of the default gateway gateway_itf = netifaces.gateways()['default'][netifaces.AF_INET][1] # IP address for the interface return netifaces.ifaddresses(gateway_itf)[netifaces.AF_INET][0]['addr'] else: raise KeyError, 'On FreeBSD, this would segfault' def close(self): if zeroconf_tag: self.zeroconf.unregister_service(self.info) self.zeroconf.close()
def __init__(self, callback): self.callback = callback self.connections = [] zeroconf = Zeroconf() listener = self browser = ServiceBrowser(zeroconf, "_ptp._tcp.local.", listener) browser = ServiceBrowser(zeroconf, "_http._tcp.local.", listener) browser = ServiceBrowser(zeroconf, "_dlna._tcp.local.", listener) browser = ServiceBrowser(zeroconf, "_daap._tcp.local.", listener) browser = ServiceBrowser(zeroconf, "_dacp._tcp.local.", listener) browser = ServiceBrowser(zeroconf, "_touch-able._tcp.local.", listener) browser = ServiceBrowser(zeroconf, "_rsp._tcp.local.", listener) browser = ServiceBrowser(zeroconf, "_rsp._tcp.local.", listener) try: input("Press enter to exit...\n\n") finally: zeroconf.close()
class Advertisement(object): def __init__(self, ip=None): """ :ip: if string `ip` given, register on given IP (if None: default route's IP). """ self.zeroconf = Zeroconf() self.info = build_service_info(ip=ip or main_ip()) def register(self): """Registers the service on the network. """ self.zeroconf.register_service(self.info) log.debug("Registered {} on {}:{}".format(self.info.name, self.ip, self.info.port)) def unregister(self): """Unregisters the service. """ self.zeroconf.unregister_service(self.info) log.debug("Unregistered touchoscbridge.") def update(self, ip=None): """Re-register the the service on the network. :ip: if string `ip` is given, use given IP when registering. """ self.unregister() self.info = build_service_info(ip=ip or main_ip()) self.register() def close(self): """Free resources. Advertisement.unregister() should be called before closing. """ self.zeroconf.close() def get_ip(self): """:return: the service's IP as a string. """ return socket.inet_ntoa(self.info.address) ip = property(get_ip)
class GlancesAutoDiscoverClient(object): """Implementation of the zeroconf protocol (client side for the Glances server).""" def __init__(self, hostname, args=None): if zeroconf_tag: zeroconf_bind_address = args.bind_address try: self.zeroconf = Zeroconf() except socket.error as e: logger.error("Cannot start zeroconf: {0}".format(e)) if netifaces_tag: # -B @ overwrite the dynamic IPv4 choice if zeroconf_bind_address == '0.0.0.0': zeroconf_bind_address = self.find_active_ip_address() else: logger.error("Couldn't find the active IP address: netifaces library not found.") logger.info("Announce the Glances server on the LAN (using {0} IP address)".format(zeroconf_bind_address)) print("Announce the Glances server on the LAN (using {0} IP address)".format(zeroconf_bind_address)) self.info = ServiceInfo( zeroconf_type, '{0}:{1}.{2}'.format(hostname, args.port, zeroconf_type), address=socket.inet_aton(zeroconf_bind_address), port=args.port, weight=0, priority=0, properties={}, server=hostname) self.zeroconf.register_service(self.info) else: logger.error("Cannot announce Glances server on the network: zeroconf library not found.") def find_active_ip_address(self): """Try to find the active IP addresses.""" try: # Interface of the default gateway gateway_itf = netifaces.gateways()['default'][netifaces.AF_INET][1] # IP address for the interface return netifaces.ifaddresses(gateway_itf)[netifaces.AF_INET][0]['addr'] except Exception: return None def close(self): if zeroconf_tag: self.zeroconf.unregister_service(self.info) self.zeroconf.close()
def main(args): try: # FIXME: Maybe we should not use zeroconf and instead implement # our own avahi browser. zeroconf = Zeroconf() client = _StoqClient() client.show_all() ServiceBrowser(zeroconf, '%s.local.' % (AVAHI_STYPE, ), client) gtk.gdk.threads_init() gtk.main() finally: zeroconf.close() env = os.environ.copy() env['PYTHONPATH'] = ':'.join( client.python_paths + [env.get('PYTHONPATH', '')]) args = [sys.executable, client.executable_path, '-f', client.conf_path] os.execve(args[0], args, env)
def host_list(): try: service_type = request.args['serviceType'] duration = request.args['duration'] except KeyError: print "No service_type or duration in request" raise zconf = Zeroconf() listener = ServiceListener() try: browser = ServiceBrowser(zconf, service_type, listener=listener) time.sleep(float(duration)) hosts = listener.services try: zconf.close() except Exception, e: pass return jsonify(hosts=hosts)
def zeroconf_scan(listener, max_time=2, max_devices=None): """ Use zeroconf to scan the local network for NRP sensors. :param ZeroconfListener listener: This object will be invoked for every Zeroconf device discovered :param float max_time: The maximum time we will wait, in seconds :param int max_devices: Stop the search after this many devices have been found :return: A list of ZeroconfInfo objects describing the found devices. """ from zeroconf import Zeroconf, ServiceBrowser z = Zeroconf() listener.max_devices = max_devices try: ServiceBrowser(z, listener.service_name, listener) listener.stop_search.wait(max_time) finally: z.close() return listener.found_sensors
class ServiceDiscoveryServer: def __init__(self, port): inet = netifaces.AF_INET hostname = socket.gethostname() def_gw = netifaces.gateways()['default'][inet][1] addr = netifaces.ifaddresses(def_gw)[inet][0]['addr'] addr = socket.inet_aton(addr) self.zeroconf = Zeroconf() self.info = ServiceInfo( SRV_TYPE, srv_fqname(), addr, port, 0, 0, {}, '{}.local.'.format(hostname) ) def start(self): self.zeroconf.register_service(self.info) def stop(self): self.zeroconf.unregister_service(self.info) self.zeroconf.close()
def test_integration_with_listener(self): type_ = "_test-srvc-type._tcp.local." name = "xxxyyy" registration_name = "%s.%s" % (name, type_) 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_types = ZeroconfServiceTypes.find(interfaces=['127.0.0.1'], timeout=0.5) assert type_ in service_types service_types = ZeroconfServiceTypes.find(zc=zeroconf_registrar, timeout=0.5) assert type_ in service_types finally: zeroconf_registrar.close()
class Broadcast(object): """ A zeroconf listener that broadcasts the address for the printing service """ def __init__(self, address, port): self.address = address self.port = port self.properties = { 'nickname': u'Printer Nickname', 'service': u'Tryton POS' } self.service = Zeroconf() self._service_info = None @property def service_info(self): if self._service_info is None: self._service_info = ServiceInfo( "_trytonpos._tcp.local.", "%s._trytonpos._tcp.local." % socket.gethostname(), socket.inet_aton(self.address), self.port, 0, 0, self.properties ) return self._service_info def register_zeroconf(self): """ Register a new service for printing """ print("Registration of service @ %s:%s" % (self.address, self.port)) self.service.registerService(self.service_info) def unregister_zeroconf(self): """ Unregister the given service """ print("Unregistering...") self.service.unregisterService(self.service_info) self.service.close()
def discover_chromecasts(max_devices=None, timeout=DISCOVER_TIMEOUT): """ Discover chromecasts on the network. """ try: zconf = Zeroconf() listener = CastListener() browser = ServiceBrowser(zconf, "_googlecast._tcp.local.", listener) if max_devices is None: time.sleep(timeout) return listener.devices else: start = time.time() while (time.time() - start < timeout and listener.count < max_devices): time.sleep(.1) return listener.devices finally: browser.cancel() zconf.close()
def test_integration(): service_added = Event() service_removed = Event() type_ = "_http._tcp.local." registration_name = "xxxyyy.%s" % type_ class MyListener(object): def remove_service(self, zeroconf, type_, name): if name == registration_name: service_removed.set() def add_service(self, zeroconf, type_, name): if name == registration_name: service_added.set() zeroconf_browser = Zeroconf() listener = MyListener() browser = ServiceBrowser(zeroconf_browser, type_, listener) zeroconf_registrar = Zeroconf() 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() zeroconf_registrar.unregister_service(info) service_removed.wait(1) assert service_removed.is_set() finally: zeroconf_registrar.close() browser.cancel() zeroconf_browser.close()
def main(args): try: # FIXME: Maybe we should not use zeroconf and instead implement # our own avahi browser. zeroconf = Zeroconf() client = _StoqClient() client.show_all() ServiceBrowser(zeroconf, '%s.local.' % (AVAHI_STYPE, ), client) gtk.gdk.threads_init() gtk.main() finally: zeroconf.close() env = os.environ.copy() env['PYTHONPATH'] = ':'.join( client.python_paths + [env.get('PYTHONPATH', '')]) popen = subprocess.Popen([sys.executable, client.executable_path], env=env) try: popen.communicate() except KeyboardInterrupt: popen.terminate()