def test_parse_interfaces(self): with mock.patch('aioupnp.interfaces.get_netifaces') as patch: patch.return_value = mock_netifaces lan, gateway = UPnP.get_lan_and_gateway(interface_name='test0') self.assertEqual(gateway, '192.168.1.1') self.assertEqual(lan, '192.168.1.2')
def get_help(command: str) -> str: annotations, doc = UPnP.get_annotations(command) doc = doc or "" arg_strs = [] for k, v in annotations.items(): if k not in ['return', 'igd_args', 'loop']: t = str(v) if not hasattr(v, "__name__") else v.__name__ if t == 'bool': arg_strs.append(f"[--{k}]") else: arg_strs.append(f"[--{k}=<{t}>]") elif k == 'igd_args': arg_strs.append(f"[--<header key>=<header value>, ...]") params = " ".join(arg_strs) usage = "\n".join(textwrap.wrap( f"aioupnp [-h] [--debug_logging] {command} {params}", 100, subsequent_indent=' ', break_long_words=False)) + "\n" return usage + textwrap.dedent(doc)
def main(argv=None, loop=None): argv = argv or sys.argv commands = [n for n in dir(UPnP) if hasattr(getattr(UPnP, n, None), "_cli")] help_str = "\n".join(textwrap.wrap( " | ".join(commands), 100, initial_indent=' ', subsequent_indent=' ', break_long_words=False )) usage = \ "\n%s\n" \ "If m-search headers are provided as keyword arguments all of the headers to be used must be provided,\n" \ "in the order they are to be used. For example:\n" \ " aioupnp --HOST=239.255.255.250:1900 --MAN=\"ssdp:discover\" --MX=1 --ST=upnp:rootdevice m_search\n\n" \ "Commands:\n" \ "%s\n\n" \ "For help with a specific command:" \ " aioupnp help <command>\n" % (base_usage, help_str) args = argv[1:] if args[0] in ['help', '-h', '--help']: if len(args) > 1: if args[1] in commands: sys.exit(get_help(args[1])) sys.exit(print(usage)) defaults = { 'debug_logging': False, 'interface': 'default', 'gateway_address': '', 'lan_address': '', 'timeout': 30, 'unicast': False } options = OrderedDict() command = None for arg in args: if arg.startswith("--"): if "=" in arg: k, v = arg.split("=") else: k, v = arg, True k = k.lstrip('--') options[k] = v else: command = arg break if not command: print("no command given") sys.exit(print(usage)) kwargs = {} for arg in args[len(options)+1:]: if arg.startswith("--"): k, v = arg.split("=") k = k.lstrip('--') kwargs[k] = v else: break for k, v in defaults.items(): if k not in options: options[k] = v if options.pop('debug_logging'): log.setLevel(logging.DEBUG) UPnP.run_cli( command.replace('-', '_'), options, options.pop('lan_address'), options.pop('gateway_address'), options.pop('timeout'), options.pop('interface'), options.pop('unicast'), kwargs, loop )
def _maintain_redirects(self): # setup the gateway if necessary if not self.upnp: try: self.upnp = yield from_future(UPnP.discover()) log.info("found upnp gateway: %s", self.upnp.gateway.manufacturer_string) except Exception as err: log.warning("upnp discovery failed: %s", err) return # update the external ip try: external_ip = yield from_future(self.upnp.get_external_ip()) if external_ip == "0.0.0.0": log.warning( "upnp doesn't know the external ip address (returned 0.0.0.0), using fallback" ) external_ip = CS.get_external_ip() if self.external_ip and self.external_ip != external_ip: log.info("external ip changed from %s to %s", self.external_ip, external_ip) elif not self.external_ip: log.info("got external ip: %s", external_ip) self.external_ip = external_ip except (asyncio.TimeoutError, UPnPError): pass if not self.upnp_redirects: # setup missing redirects try: upnp_redirects = yield DeferredDict({ "UDP": from_future( self.upnp.get_next_mapping(self._int_dht_node_port, "UDP", "LBRY DHT port")), "TCP": from_future( self.upnp.get_next_mapping(self._int_peer_port, "TCP", "LBRY peer port")) }) self.upnp_redirects.update(upnp_redirects) except (asyncio.TimeoutError, UPnPError): self.upnp = None return self._maintain_redirects() else: # check existing redirects are still active found = set() mappings = yield from_future(self.upnp.get_redirects()) for mapping in mappings: proto = mapping['NewProtocol'] if proto in self.upnp_redirects and mapping[ 'NewExternalPort'] == self.upnp_redirects[proto]: if mapping['NewInternalClient'] == self.upnp.lan_address: found.add(proto) if 'UDP' not in found: try: udp_port = yield from_future( self.upnp.get_next_mapping(self._int_dht_node_port, "UDP", "LBRY DHT port")) self.upnp_redirects['UDP'] = udp_port log.info("refreshed upnp redirect for dht port: %i", udp_port) except (asyncio.TimeoutError, UPnPError): del self.upnp_redirects['UDP'] if 'TCP' not in found: try: tcp_port = yield from_future( self.upnp.get_next_mapping(self._int_peer_port, "TCP", "LBRY peer port")) self.upnp_redirects['TCP'] = tcp_port log.info("refreshed upnp redirect for peer port: %i", tcp_port) except (asyncio.TimeoutError, UPnPError): del self.upnp_redirects['TCP'] if 'TCP' in self.upnp_redirects and 'UDP' in self.upnp_redirects: log.debug("upnp redirects are still active")
def _maintain_redirects(self): # setup the gateway if necessary if not self.upnp: try: self.upnp = yield from_future(UPnP.discover()) log.info("found upnp gateway: %s", self.upnp.gateway.manufacturer_string) except Exception as err: log.warning("upnp discovery failed: %s", err) self.upnp = None # update the external ip external_ip = None if self.upnp: try: external_ip = yield from_future(self.upnp.get_external_ip()) if external_ip != "0.0.0.0" and not self.external_ip: log.info("got external ip from UPnP: %s", external_ip) except (asyncio.TimeoutError, UPnPError): pass if external_ip == "0.0.0.0" or not external_ip: log.warning( "unable to get external ip from UPnP, checking lbry.io fallback" ) external_ip = yield CS.get_external_ip() if self.external_ip and self.external_ip != external_ip: log.info("external ip changed from %s to %s", self.external_ip, external_ip) self.external_ip = external_ip assert self.external_ip is not None # TODO: handle going/starting offline if not self.upnp_redirects and self.upnp: # setup missing redirects try: log.info("add UPnP port mappings") d = {} if PEER_PROTOCOL_SERVER_COMPONENT not in self.component_manager.skip_components: d["TCP"] = from_future( self.upnp.get_next_mapping(self._int_peer_port, "TCP", "LBRY peer port")) if DHT_COMPONENT not in self.component_manager.skip_components: d["UDP"] = from_future( self.upnp.get_next_mapping(self._int_dht_node_port, "UDP", "LBRY DHT port")) upnp_redirects = yield DeferredDict(d) log.info("set up redirects: %s", upnp_redirects) self.upnp_redirects.update(upnp_redirects) except (asyncio.TimeoutError, UPnPError): self.upnp = None return self._maintain_redirects() elif self.upnp: # check existing redirects are still active found = set() mappings = yield from_future(self.upnp.get_redirects()) for mapping in mappings: proto = mapping['NewProtocol'] if proto in self.upnp_redirects and mapping[ 'NewExternalPort'] == self.upnp_redirects[proto]: if mapping['NewInternalClient'] == self.upnp.lan_address: found.add(proto) if 'UDP' not in found and DHT_COMPONENT not in self.component_manager.skip_components: try: udp_port = yield from_future( self.upnp.get_next_mapping(self._int_dht_node_port, "UDP", "LBRY DHT port")) self.upnp_redirects['UDP'] = udp_port log.info("refreshed upnp redirect for dht port: %i", udp_port) except (asyncio.TimeoutError, UPnPError): del self.upnp_redirects['UDP'] if 'TCP' not in found and PEER_PROTOCOL_SERVER_COMPONENT not in self.component_manager.skip_components: try: tcp_port = yield from_future( self.upnp.get_next_mapping(self._int_peer_port, "TCP", "LBRY peer port")) self.upnp_redirects['TCP'] = tcp_port log.info("refreshed upnp redirect for peer port: %i", tcp_port) except (asyncio.TimeoutError, UPnPError): del self.upnp_redirects['TCP'] if ('TCP' in self.upnp_redirects and PEER_PROTOCOL_SERVER_COMPONENT not in self.component_manager.skip_components) and ( 'UDP' in self.upnp_redirects and DHT_COMPONENT not in self.component_manager.skip_components): if self.upnp_redirects: log.debug("upnp redirects are still active")