diff --git a/deluge/core/preferencesmanager.py b/deluge/core/preferencesmanager.py index c3942873f..4372bd4ac 100644 --- a/deluge/core/preferencesmanager.py +++ b/deluge/core/preferencesmanager.py @@ -10,6 +10,7 @@ import logging import os +import random import threading from twisted.internet.task import LoopingCall @@ -31,13 +32,18 @@ DEFAULT_PREFS = { "download_location": deluge.common.get_default_download_dir(), "listen_ports": [6881, 6891], "listen_interface": "", + "random_port": True, + "listen_random_port": None, + "listen_use_sys_port": False, + "listen_reuse_port": True, + "outgoing_ports": [0, 0], + "random_outgoing_ports": True, "copy_torrent_file": False, "del_copy_torrent_file": False, "torrentfiles_location": deluge.common.get_default_download_dir(), "plugins_location": os.path.join(deluge.configmanager.get_config_dir(), "plugins"), "prioritize_first_last_pieces": False, "sequential_download": False, - "random_port": True, "dht": True, "upnp": True, "natpmp": True, @@ -96,8 +102,6 @@ DEFAULT_PREFS = { "hostname": "", "port": 0 }, - "outgoing_ports": [0, 0], - "random_outgoing_ports": True, "peer_tos": "0x00", "rate_limit_ip_overhead": True, "anonymous_mode": False, @@ -126,8 +130,15 @@ class PreferencesManager(component.Component): self.new_release_timer = None def start(self): + # Setup listen port followed by dht to ensure both use same port. + self.__set_listen_on() + self._on_set_dht("dht", self.config["dht"]) + # Set the initial preferences on start-up for key in DEFAULT_PREFS: + # Listen port and dht already setup in correct order so skip running again. + if key in ("dht", "random_port") or key.startswith("listen_"): + continue self.do_config_set_func(key, self.config[key]) self.config.register_change_callback(self._on_config_value_change) @@ -160,56 +171,51 @@ class PreferencesManager(component.Component): log.debug("Unable to make directory: %s", ex) def _on_set_listen_ports(self, key, value): - # Only set the listen ports if random_port is not true - if self.config["random_port"] is not True: - log.debug("listen port range set to %s-%s", value[0], value[1]) - try: - self.session.listen_on( - value[0], value[1], str(self.config["listen_interface"]) - ) - except RuntimeError as ex: - log.warn("Error on call to session.listen_on(%s, %s, %s): %s", - value[0], value[1], str(self.config["listen_interface"]), ex) + self.__set_listen_on() def _on_set_listen_interface(self, key, value): - # Call the random_port callback since it'll do what we need - self._on_set_random_port("random_port", self.config["random_port"]) + self.__set_listen_on() def _on_set_random_port(self, key, value): - log.debug("random port value set to %s", value) - # We need to check if the value has been changed to true and false - # and then handle accordingly. - if value: - import random - listen_ports = [] + self.__set_listen_on() - def randrange(): - return random.randrange(49152, 65525) - listen_ports.append(randrange()) - listen_ports.append(listen_ports[0] + 10) + def __set_listen_on(self): + """ Set the ports and interface address to listen for incoming connections on.""" + if self.config["random_port"]: + if not self.config["listen_random_port"]: + self.config["listen_random_port"] = random.randrange(49152, 65525) + listen_ports = [self.config["listen_random_port"]] * 2 # use single port range else: + self.config["listen_random_port"] = None listen_ports = self.config["listen_ports"] - # Set the listen ports - log.info("listen port range set to %s-%s on interface '%s'", listen_ports[0], - listen_ports[1], str(self.config["listen_interface"])) + # If a single port range then always enable re-use port flag. + reuse_port = True if listen_ports[0] == listen_ports[1] else self.config["listen_reuse_port"] + flags = ((lt.listen_on_flags_t.listen_no_system_port + if not self.config["listen_use_sys_port"] else 0) | + (lt.listen_on_flags_t.listen_reuse_address + if reuse_port else 0)) + interface = str(self.config["listen_interface"].strip()) + + log.debug("Listen Interface: %s, Ports: %s with reuse_port: %s, use_sys_port: %s", + interface, listen_ports, reuse_port, self.config["listen_use_sys_port"]) try: - self.session.listen_on( - listen_ports[0], listen_ports[1], - str(self.config["listen_interface"]) - ) + self.session.listen_on(listen_ports[0], listen_ports[1], interface, flags) except RuntimeError as ex: - log.warn("Error on call to session.listen_on(%s, %s, %s): %s", - listen_ports[0], listen_ports[1], str(self.config["listen_interface"]), ex) + if ex.message == "Invalid Argument": + log.error("Error setting listen interface (must be IP Address): %s %s-%s", + interface, listen_ports[0], listen_ports[1]) def _on_set_outgoing_ports(self, key, value): - if not self.config["random_outgoing_ports"]: - log.debug("outgoing port range set to %s-%s", value[0], value[1]) - self.session_set_setting("outgoing_ports", (value[0], value[1])) + self.__set_outgoing_ports() def _on_set_random_outgoing_ports(self, key, value): - if value: - self.session.outgoing_ports(0, 0) + self.__set_outgoing_ports() + + def __set_outgoing_ports(self): + ports = [0, 0] if self.config["random_outgoing_ports"] else self.config["outgoing_ports"] + log.debug("Outgoing ports set to %s", ports) + self.session_set_setting("outgoing_ports", (ports[0], ports[1])) def _on_set_peer_tos(self, key, value): log.debug("setting peer_tos to: %s", value)