def resolve(uri, hmac_key=None): """ Resolve a 'magic' uri (PYRONAME, PYROMETA) into the direct PYRO uri. It finds a name server, and use that to resolve a PYRONAME uri into the direct PYRO uri pointing to the named object. If uri is already a PYRO uri, it is returned unmodified. You can consider this a shortcut function so that you don't have to locate and use a name server proxy yourself. Note: if you need to resolve more than a few names, consider using the name server directly instead of repeatedly calling this function, to avoid the name server lookup overhead from each call. """ if isinstance(uri, basestring): uri = core.URI(uri) elif not isinstance(uri, core.URI): raise TypeError("can only resolve Pyro URIs") if uri.protocol == "PYRO": return uri log.debug("resolving %s", uri) if uri.protocol == "PYRONAME": with locateNS(uri.host, uri.port, hmac_key=hmac_key) as nameserver: return nameserver.lookup(uri.object) elif uri.protocol == "PYROMETA": with locateNS(uri.host, uri.port, hmac_key=hmac_key) as nameserver: candidates = nameserver.list(metadata_all=uri.object) if candidates: candidate = random.choice(list(candidates.values())) log.debug("resolved to candidate %s", candidate) return core.URI(candidate) raise NamingError( "no registrations available with desired metadata properties %s" % uri.object) else: raise PyroError("invalid uri protocol")
def run(self): while not self.stop: time.sleep(self.loop_delay) time_since_last_autoclean = time.time() - self.last_cleaned if time_since_last_autoclean < config.NS_AUTOCLEAN: continue for name, uri in self.nameserver.list().items(): if name in (constants.DAEMON_NAME, constants.NAMESERVER_NAME): continue try: uri_obj = core.URI(uri) timeout = config.COMMTIMEOUT or 5 sock = socketutil.createSocket(connect=(uri_obj.host, uri_obj.port), timeout=timeout) sock.close() # if we get here, the listed server is still answering on its port if name in self.unreachable: del self.unreachable[name] except socket.error: if name not in self.unreachable: self.unreachable[name] = time.time() if time.time() - self.unreachable[name] >= self.max_unreachable_time: log.info("autoclean: unregistering %s; cannot connect uri %s for %d sec", name, uri, self.max_unreachable_time) self.nameserver.remove(name) del self.unreachable[name] continue self.last_cleaned = time.time() if self.unreachable: log.debug("autoclean: %d/%d names currently unreachable", len(self.unreachable), self.nameserver.count())
def processRequest(self): try: data, addr = self.sock.recvfrom(100) if data == b"GET_NSURI": responsedata = core.URI(self.nsUri) if responsedata.host == "0.0.0.0": # replace INADDR_ANY address by the interface IP address that connects to the requesting client try: interface_ip = socketutil.getInterfaceAddress(addr[0]) responsedata.host = interface_ip except socket.error: pass log.debug( "responding to broadcast request from %s: interface %s", addr[0], responsedata.host) responsedata = str(responsedata).encode("iso-8859-1") self.sock.sendto(responsedata, 0, addr) except socket.error: pass except SystemError: if sys.platform == "cli" and not self.running: # ironpython throws these systemerrors when shutting down... we can ignore them. pass else: raise
def lookup(self, name, return_metadata=False): """ Lookup the given name, returns an URI if found. Returns tuple (uri, metadata) if return_metadata is True. """ try: uri, metadata = self.storage[name] uri = core.URI(uri) if return_metadata: metadata = list(metadata) if metadata else [] return uri, metadata return uri except KeyError: raise NamingError("unknown name: " + name)
def register(self, name, uri, safe=False): """Register a name with an URI. If safe is true, name cannot be registered twice. The uri can be a string or an URI object.""" if isinstance(uri, core.URI): uri = uri.asString() elif not isinstance(uri, basestring): raise TypeError("only URIs or strings can be registered") else: core.URI(uri) # check if uri is valid if not isinstance(name, basestring): raise TypeError("name must be a str") if safe and name in self.namespace: raise NamingError("name already registered: " + name) with self.lock: self.namespace[name] = uri
def resolve(uri): """Resolve a 'magic' uri (PYRONAME) into the direct PYRO uri.""" if isinstance(uri, basestring): uri = core.URI(uri) elif not isinstance(uri, core.URI): raise TypeError("can only resolve Pyro URIs") if uri.protocol == "PYRO": return uri log.debug("resolving %s", uri) if uri.protocol == "PYRONAME": nameserver = locateNS(uri.host, uri.port) uri = nameserver.lookup(uri.object) nameserver._pyroRelease() return uri else: raise PyroError("invalid uri protocol")
def processRequest(self): try: data, addr = self.sock.recvfrom(100) if data == self.REQUEST_NSURI: responsedata = core.URI(self.nsUri) if responsedata.host == "0.0.0.0": # replace INADDR_ANY address by the interface IP adress that connects to the requesting client try: interface_ip = socketutil.getInterfaceAddress(addr[0]) responsedata.host = interface_ip except socket.error: pass log.debug( "responding to broadcast request from %s: interface %s", addr[0], responsedata.host) responsedata = str(responsedata).encode("iso-8859-1") self.sock.sendto(responsedata, 0, addr) except socket.error: pass
def register(self, name, uri, safe=False, metadata=None): """Register a name with an URI. If safe is true, name cannot be registered twice. The uri can be a string or an URI object. Metadata must be None, or a collection of strings.""" if isinstance(uri, core.URI): uri = uri.asString() elif not isinstance(uri, basestring): raise TypeError("only URIs or strings can be registered") else: core.URI(uri) # check if uri is valid if not isinstance(name, basestring): raise TypeError("name must be a str") if isinstance(metadata, basestring): raise TypeError("metadata should not be a str, but another iterable (set, list, etc)") metadata and iter(metadata) # validate that metadata is iterable with self.lock: if safe and name in self.storage: raise NamingError("name already registered: " + name) if metadata: metadata = set(metadata) self.storage[name] = uri, metadata
def resolve(uri, hmac_key=None): """ Resolve a 'magic' uri (PYRONAME) into the direct PYRO uri. It finds a name server, and use that to resolve a PYRONAME uri into the direct PYRO uri pointing to the named object. If uri is already a PYRO uri, it is returned unmodified. You can consider this a shortcut function so that you don't have to locate and use a name server proxy yourself. Note: if you need to resolve more than a few names, consider using the name server directly instead of repeatedly calling this function, to avoid the name server lookup overhead from each call. """ if isinstance(uri, basestring): uri = core.URI(uri) elif not isinstance(uri, core.URI): raise TypeError("can only resolve Pyro URIs") if uri.protocol == "PYRO": return uri log.debug("resolving %s", uri) if uri.protocol == "PYRONAME": nameserver = locateNS(uri.host, uri.port, hmac_key=hmac_key) uri = nameserver.lookup(uri.object) nameserver._pyroRelease() return uri else: raise PyroError("invalid uri protocol")
def locateNS(host=None, port=None): """Get a proxy for a name server somewhere in the network.""" if host is None: # first try localhost if we have a good chance of finding it there if Pyro4.config.NS_HOST in ( "localhost", "::1") or Pyro4.config.NS_HOST.startswith("127."): host = Pyro4.config.NS_HOST if ":" in host: # ipv6 host = "[%s]" % host uristring = "PYRO:%s@%s:%d" % (constants.NAMESERVER_NAME, host, port or Pyro4.config.NS_PORT) log.debug("locating the NS: %s", uristring) proxy = core.Proxy(uristring) try: proxy.ping() log.debug("located NS") return proxy except PyroError: pass # broadcast lookup if not port: port = Pyro4.config.NS_BCPORT log.debug("broadcast locate") sock = Pyro4.socketutil.createBroadcastSocket( reuseaddr=Pyro4.config.SOCK_REUSE, timeout=0.7) for _ in range(3): try: for bcaddr in Pyro4.config.parseAddressesString( Pyro4.config.BROADCAST_ADDRS): try: sock.sendto(BroadcastServer.REQUEST_NSURI, 0, (bcaddr, port)) except socket.error: x = sys.exc_info()[1] err = getattr(x, "errno", x.args[0]) if err not in Pyro4.socketutil.ERRNO_EADDRNOTAVAIL: # yeah, windows likes to throw these... if err not in Pyro4.socketutil.ERRNO_EADDRINUSE: # and jython likes to throw thses... raise data, _ = sock.recvfrom(100) try: sock.shutdown(socket.SHUT_RDWR) except (OSError, socket.error): pass sock.close() if sys.version_info >= (3, 0): data = data.decode("iso-8859-1") log.debug("located NS: %s", data) return core.Proxy(data) except socket.timeout: continue try: sock.shutdown(socket.SHUT_RDWR) except (OSError, socket.error): pass sock.close() log.debug("broadcast locate failed, try direct connection on NS_HOST") # broadcast failed, try PYRO directly on specific host host = Pyro4.config.NS_HOST port = Pyro4.config.NS_PORT # pyro direct lookup if not port: port = Pyro4.config.NS_PORT if ":" in host: host = "[%s]" % host if core.URI.isUnixsockLocation(host): uristring = "PYRO:%s@%s" % (constants.NAMESERVER_NAME, host) else: uristring = "PYRO:%s@%s:%d" % (constants.NAMESERVER_NAME, host, port) uri = core.URI(uristring) log.debug("locating the NS: %s", uri) proxy = core.Proxy(uri) try: proxy.ping() log.debug("located NS") return proxy except PyroError as x: e = NamingError("Failed to locate the nameserver") e.__cause__ = x raise e
def lookup(self, name): """Lookup the given name, returns an URI if found""" try: return core.URI(self.namespace[name]) except KeyError: raise NamingError("unknown name: " + name)
def locateNS(host=None, port=None, broadcast=True, hmac_key=None): """Get a proxy for a name server somewhere in the network.""" if host is None: # first try localhost if we have a good chance of finding it there if Pyro4.config.NS_HOST in ( "localhost", "::1") or Pyro4.config.NS_HOST.startswith("127."): if ":" in Pyro4.config.NS_HOST: # ipv6 hosts = ["[%s]" % Pyro4.config.NS_HOST] else: # Some systems (Debian Linux) have 127.0.1.1 in the hosts file assigned to the hostname, # try this too for convenience sake (only if it's actually used as a valid ip address) try: socket.gethostbyaddr("127.0.1.1") hosts = [Pyro4.config.NS_HOST ] if Pyro4.config.NS_HOST == "127.0.1.1" else [ Pyro4.config.NS_HOST, "127.0.1.1" ] except socket.error: hosts = [Pyro4.config.NS_HOST] for host in hosts: uristring = "PYRO:%s@%s:%d" % (Pyro4.constants.NAMESERVER_NAME, host, port or Pyro4.config.NS_PORT) log.debug("locating the NS: %s", uristring) proxy = core.Proxy(uristring) proxy._pyroHmacKey = hmac_key try: proxy._pyroBind() log.debug("located NS") return proxy except PyroError: pass if broadcast: # broadcast lookup if not port: port = Pyro4.config.NS_BCPORT log.debug("broadcast locate") sock = Pyro4.socketutil.createBroadcastSocket( reuseaddr=Pyro4.config.SOCK_REUSE, timeout=0.7) for _ in range(3): try: for bcaddr in Pyro4.config.parseAddressesString( Pyro4.config.BROADCAST_ADDRS): try: sock.sendto(BroadcastServer.REQUEST_NSURI, 0, (bcaddr, port)) except socket.error: x = sys.exc_info()[1] err = getattr(x, "errno", x.args[0]) # handle some errno's that some platforms like to throw: if err not in Pyro4.socketutil.ERRNO_EADDRNOTAVAIL and err not in Pyro4.socketutil.ERRNO_EADDRINUSE: raise data, _ = sock.recvfrom(100) sock.close() if sys.version_info >= (3, 0): data = data.decode("iso-8859-1") log.debug("located NS: %s", data) proxy = core.Proxy(data) proxy._pyroHmacKey = hmac_key return proxy except socket.timeout: continue try: sock.shutdown(socket.SHUT_RDWR) except (OSError, socket.error): pass sock.close() log.debug( "broadcast locate failed, try direct connection on NS_HOST") else: log.debug("skipping broadcast lookup") # broadcast failed or skipped, try PYRO directly on specific host host = Pyro4.config.NS_HOST port = Pyro4.config.NS_PORT # pyro direct lookup if not port: port = Pyro4.config.NS_PORT if core.URI.isUnixsockLocation(host): uristring = "PYRO:%s@%s" % (Pyro4.constants.NAMESERVER_NAME, host) else: # if not a unix socket, check for ipv6 if ":" in host: host = "[%s]" % host uristring = "PYRO:%s@%s:%d" % (Pyro4.constants.NAMESERVER_NAME, host, port) uri = core.URI(uristring) log.debug("locating the NS: %s", uri) proxy = core.Proxy(uri) proxy._pyroHmacKey = hmac_key try: proxy._pyroBind() log.debug("located NS") return proxy except PyroError as x: e = NamingError("Failed to locate the nameserver") if sys.version_info >= (3, 0): e.__cause__ = x raise e