From a19de3ca525b44b223a55e84be2153ba552364bf Mon Sep 17 00:00:00 2001 From: drew2a Date: Fri, 29 Jan 2021 12:12:50 +0100 Subject: [PATCH 1/5] Set Organisation for QSettings --- src/tribler-gui/tribler_gui/tribler_window.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tribler-gui/tribler_gui/tribler_window.py b/src/tribler-gui/tribler_gui/tribler_window.py index 8a8a51bb9c..569663b3a8 100644 --- a/src/tribler-gui/tribler_gui/tribler_window.py +++ b/src/tribler-gui/tribler_gui/tribler_window.py @@ -108,7 +108,7 @@ def __init__(self, core_args=None, core_env=None, api_port=None, api_key=None): self.setWindowIcon(QIcon(QPixmap(get_image_path('tribler.png')))) - self.gui_settings = QSettings() + self.gui_settings = QSettings('nl.tudelft.tribler') api_port = api_port or int(get_gui_setting(self.gui_settings, "api_port", DEFAULT_API_PORT)) api_key = api_key or get_gui_setting(self.gui_settings, "api_key", hexlify(os.urandom(16)).encode('utf-8')) self.gui_settings.setValue("api_key", api_key) From fc604cec9d308fe85701f5570a3d073fabd7342a Mon Sep 17 00:00:00 2001 From: drew2a Date: Fri, 29 Jan 2021 12:13:20 +0100 Subject: [PATCH 2/5] Change default API port to 52194 --- src/tribler-gui/tribler_gui/defs.py | 2 +- src/tribler-gui/tribler_gui/i18n/pt_BR.ts | 4 ++-- src/tribler-gui/tribler_gui/qt_resources/mainwindow.ui | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tribler-gui/tribler_gui/defs.py b/src/tribler-gui/tribler_gui/defs.py index 3a153a34a9..4a7b03ab09 100644 --- a/src/tribler-gui/tribler_gui/defs.py +++ b/src/tribler-gui/tribler_gui/defs.py @@ -5,7 +5,7 @@ DEFAULT_API_PROTOCOL = "http" DEFAULT_API_HOST = "localhost" -DEFAULT_API_PORT = 8085 +DEFAULT_API_PORT = 52194 # Define stacked widget page indices PAGE_SEARCH_RESULTS = 0 diff --git a/src/tribler-gui/tribler_gui/i18n/pt_BR.ts b/src/tribler-gui/tribler_gui/i18n/pt_BR.ts index afec7738be..db292b9c27 100644 --- a/src/tribler-gui/tribler_gui/i18n/pt_BR.ts +++ b/src/tribler-gui/tribler_gui/i18n/pt_BR.ts @@ -1238,8 +1238,8 @@ per download - Port (defaults to 8085) - Porta (padrão é 8085) + Port (defaults to 52194) + Porta (padrão é 52194) diff --git a/src/tribler-gui/tribler_gui/qt_resources/mainwindow.ui b/src/tribler-gui/tribler_gui/qt_resources/mainwindow.ui index bd3d4fc895..393b188df7 100644 --- a/src/tribler-gui/tribler_gui/qt_resources/mainwindow.ui +++ b/src/tribler-gui/tribler_gui/qt_resources/mainwindow.ui @@ -2218,7 +2218,7 @@ color: white; - Port (defaults to 8085) + Port (defaults to 52194) From 0c67fc1ca311e3c0ea683c07ed99b8e9769c00b4 Mon Sep 17 00:00:00 2001 From: drew2a Date: Wed, 3 Feb 2021 11:59:59 +0100 Subject: [PATCH 3/5] Extend network utils --- .../tribler_common}/network_utils.py | 33 +++++++++++++++---- .../tribler_core/config/tribler_config.py | 2 +- src/tribler-core/tribler_core/conftest.py | 2 +- .../tests/test_triblertunnel_community.py | 3 +- .../tribler_core/tests/test_network_utils.py | 21 +++++++++++- src/tribler-gui/tribler_gui/tests/test_gui.py | 5 +-- src/tribler-gui/tribler_gui/tribler_window.py | 4 +++ 7 files changed, 57 insertions(+), 13 deletions(-) rename src/{tribler-core/tribler_core/utilities => tribler-common/tribler_common}/network_utils.py (84%) diff --git a/src/tribler-core/tribler_core/utilities/network_utils.py b/src/tribler-common/tribler_common/network_utils.py similarity index 84% rename from src/tribler-core/tribler_core/utilities/network_utils.py rename to src/tribler-common/tribler_common/network_utils.py index 2ce3ad54c9..638fc0c9e2 100644 --- a/src/tribler-core/tribler_core/utilities/network_utils.py +++ b/src/tribler-common/tribler_common/network_utils.py @@ -7,11 +7,31 @@ import struct import sys -logger = logging.getLogger(__name__) +MAX_PORT = 65535 + +logger = logging.getLogger("NetworkUtils") CLAIMED_PORTS = [] +class FreePortNotFoundError(Exception): + pass + + +def get_first_free_port(start=5000, limit=100, family=socket.AF_INET, socket_type=socket.SOCK_STREAM): + stop = min(MAX_PORT, start + limit) + logger.info(f'Looking for first free port in range [{start}..{stop}]') + + for port in range(start, stop): + if _test_port(family, socket_type, port): + logger.info(f'{port} is free') + return port + + logger.info(f'{port} in use') + + raise FreePortNotFoundError(f'Free port not found in range [{start}..{stop}]') + + def get_random_port(socket_type="all", min_port=5000, max_port=60000): """Gets a random port number that works. @param socket_type: Type of the socket, can be "all", "tcp", or "udp". @@ -22,11 +42,11 @@ def get_random_port(socket_type="all", min_port=5000, max_port=60000): assert socket_type in ("all", "tcp", "udp"), f"Invalid socket type {type(socket_type)}" assert isinstance(min_port, int), f"Invalid min_port type {type(min_port)}" assert isinstance(max_port, int), f"Invalid max_port type {type(max_port)}" - assert 0 < min_port <= max_port <= 65535, f"Invalid min_port and mac_port values {min_port}, {max_port}" + assert 0 < min_port <= max_port <= MAX_PORT, f"Invalid min_port and mac_port values {min_port}, {max_port}" working_port = None try_port = random.randint(min_port, max_port) - while try_port <= 65535: + while try_port <= MAX_PORT: if check_random_port(try_port, socket_type): working_port = try_port break @@ -47,7 +67,7 @@ def check_random_port(port, socket_type="all"): """ assert socket_type in ("all", "tcp", "udp"), f"Invalid socket type {type(socket_type)}" assert isinstance(port, int), f"Invalid port type {type(port)}" - assert 0 < port <= 65535, f"Invalid port value {port}" + assert 0 < port <= MAX_PORT, f"Invalid port value {port}" # only support IPv4 for now _family = socket.AF_INET @@ -80,7 +100,7 @@ def _test_port(family, sock_type, port): """ assert family in (socket.AF_INET,), f"Invalid family value {family}" assert sock_type in (socket.SOCK_DGRAM, socket.SOCK_STREAM), f"Invalid sock_type value {sock_type}" - assert 0 < port <= 65535, f"Invalid port value {port}" + assert 0 < port <= MAX_PORT, f"Invalid port value {port}" try: with socket.socket(family, sock_type) as s: @@ -89,8 +109,7 @@ def _test_port(family, sock_type, port): s.bind(('', port)) is_port_working = True except OSError as e: - logger.debug("Port test failed (port=%s, family=%s, type=%s): %s", - port, family, sock_type, e) + logger.debug("Port test failed (port=%s, family=%s, type=%s): %s", port, family, sock_type, e) is_port_working = False return is_port_working diff --git a/src/tribler-core/tribler_core/config/tribler_config.py b/src/tribler-core/tribler_core/config/tribler_config.py index 2b51d7dc9f..b7693b516c 100644 --- a/src/tribler-core/tribler_core/config/tribler_config.py +++ b/src/tribler-core/tribler_core/config/tribler_config.py @@ -10,13 +10,13 @@ from validate import Validator +from tribler_common.network_utils import get_random_port from tribler_common.simpledefs import MAX_LIBTORRENT_RATE_LIMIT from tribler_core.exceptions import InvalidConfigException from tribler_core.modules.libtorrent.download_config import get_default_dest_dir from tribler_core.utilities import path_util from tribler_core.utilities.install_dir import get_lib_path -from tribler_core.utilities.network_utils import get_random_port from tribler_core.utilities.path_util import Path CONFIG_FILENAME = 'triblerd.conf' diff --git a/src/tribler-core/tribler_core/conftest.py b/src/tribler-core/tribler_core/conftest.py index 461fa15c91..782a414f49 100644 --- a/src/tribler-core/tribler_core/conftest.py +++ b/src/tribler-core/tribler_core/conftest.py @@ -10,6 +10,7 @@ import pytest +from tribler_common.network_utils import get_random_port from tribler_common.simpledefs import DLSTATUS_SEEDING from tribler_core.config.tribler_config import TriblerConfig @@ -21,7 +22,6 @@ from tribler_core.tests.tools.common import TESTS_DATA_DIR, TESTS_DIR from tribler_core.tests.tools.tracker.udp_tracker import UDPTracker from tribler_core.upgrade.db72_to_pony import DispersyToPonyMigration -from tribler_core.utilities.network_utils import get_random_port from tribler_core.utilities.unicode import hexlify diff --git a/src/tribler-core/tribler_core/modules/tunnel/tests/test_triblertunnel_community.py b/src/tribler-core/tribler_core/modules/tunnel/tests/test_triblertunnel_community.py index 66a3f8439e..10b786b870 100644 --- a/src/tribler-core/tribler_core/modules/tunnel/tests/test_triblertunnel_community.py +++ b/src/tribler-core/tribler_core/modules/tunnel/tests/test_triblertunnel_community.py @@ -19,12 +19,13 @@ from ipv8.test.mocking.ipv8 import MockIPv8 from ipv8.util import succeed +from tribler_common.network_utils import get_random_port + from tribler_core.modules.bandwidth_accounting.community import BandwidthAccountingCommunity from tribler_core.modules.tunnel.community.payload import BandwidthTransactionPayload from tribler_core.modules.tunnel.community.triblertunnel_community import PEER_FLAG_EXIT_HTTP, TriblerTunnelCommunity from tribler_core.tests.tools.base_test import MockObject from tribler_core.tests.tools.tracker.http_tracker import HTTPTracker -from tribler_core.utilities.network_utils import get_random_port from tribler_core.utilities.path_util import mkdtemp diff --git a/src/tribler-core/tribler_core/tests/test_network_utils.py b/src/tribler-core/tribler_core/tests/test_network_utils.py index 76c4b87d9e..137b3228b2 100644 --- a/src/tribler-core/tribler_core/tests/test_network_utils.py +++ b/src/tribler-core/tribler_core/tests/test_network_utils.py @@ -3,7 +3,12 @@ import pytest -from tribler_core.utilities.network_utils import autodetect_socket_style, get_random_port +from tribler_common.network_utils import ( + FreePortNotFoundError, + autodetect_socket_style, + get_first_free_port, + get_random_port, +) def test_get_random_port(): @@ -43,3 +48,17 @@ def test_get_random_port_invalid_type(): def test_autodetect_socket_style(): style = autodetect_socket_style() assert style == 0 or autodetect_socket_style() == 1 + + +def test_get_first_free_port(): + # target port is free + assert get_first_free_port(start=50000) == 50000 + + # target port is locked + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.bind(('', 50000)) + assert get_first_free_port(start=50000) == 50001 + + # no free ports found + with pytest.raises(FreePortNotFoundError): + get_first_free_port(start=50000, limit=0) diff --git a/src/tribler-gui/tribler_gui/tests/test_gui.py b/src/tribler-gui/tribler_gui/tests/test_gui.py index c618bb7ed9..2bcf74ea5c 100644 --- a/src/tribler-gui/tribler_gui/tests/test_gui.py +++ b/src/tribler-gui/tribler_gui/tests/test_gui.py @@ -9,8 +9,9 @@ import pytest +from tribler_common.network_utils import get_random_port + from tribler_core.tests.tools.common import TORRENT_UBUNTU_FILE -from tribler_core.utilities.network_utils import get_random_port import tribler_gui import tribler_gui.core_manager as core_manager @@ -63,7 +64,7 @@ def tribler_api(api_port, tmpdir_factory): def on_core_read_ready(): raw_output = bytes(core_process.readAll()) decoded_output = raw_output.decode(errors="replace") - print(decoded_output.strip()) + print(decoded_output.strip()) # noqa: T001 core_process.setProcessEnvironment(core_env) core_process.setReadChannel(QProcess.StandardOutput) diff --git a/src/tribler-gui/tribler_gui/tribler_window.py b/src/tribler-gui/tribler_gui/tribler_window.py index 569663b3a8..9446c315ed 100644 --- a/src/tribler-gui/tribler_gui/tribler_window.py +++ b/src/tribler-gui/tribler_gui/tribler_window.py @@ -37,6 +37,8 @@ QTreeWidget, ) +from tribler_common.network_utils import get_first_free_port + from tribler_core.modules.process_checker import ProcessChecker from tribler_core.utilities.unicode import hexlify from tribler_core.version import version_id @@ -112,6 +114,8 @@ def __init__(self, core_args=None, core_env=None, api_port=None, api_key=None): api_port = api_port or int(get_gui_setting(self.gui_settings, "api_port", DEFAULT_API_PORT)) api_key = api_key or get_gui_setting(self.gui_settings, "api_key", hexlify(os.urandom(16)).encode('utf-8')) self.gui_settings.setValue("api_key", api_key) + + api_port = get_first_free_port(start=api_port, limit=100) request_manager.port, request_manager.key = api_port, api_key self.tribler_started = False From 59cbffb747bdcd7c5ad98cdf08b2dcedac0c7c94 Mon Sep 17 00:00:00 2001 From: drew2a Date: Wed, 3 Feb 2021 12:04:29 +0100 Subject: [PATCH 4/5] Update port reference --- doc/restapi/introduction.rst | 6 ++++-- src/tribler-core/run_bandwidth_crawler.py | 2 +- src/tribler-core/run_tunnel_helper.py | 2 +- src/tribler-core/tribler_core/restapi/events_endpoint.py | 2 +- src/tribler-gui/tribler_gui/core_manager.py | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/restapi/introduction.rst b/doc/restapi/introduction.rst index 720bc5db7d..01f688d3de 100644 --- a/doc/restapi/introduction.rst +++ b/doc/restapi/introduction.rst @@ -16,9 +16,11 @@ Some requests require one or more parameters. These parameters are passed using .. code-block:: none - curl -X PUT -H "X-Api-Key: " http://localhost:8085/mychannel/rssfeeds/http%3A%2F%2Frssfeed.com%2Frss.xml + curl -X PUT -H "X-Api-Key: " http://localhost:52194/mychannel/rssfeeds/http%3A%2F%2Frssfeed.com%2Frss.xml -Alternatively, requests can be made using Swagger UI by starting Tribler and opening `http://localhost:8085/docs` in a browser. +Alternatively, requests can be made using Swagger UI by starting Tribler and opening `http://localhost:52194/docs` in a browser. + +Note: 52194 is a default port value. It can be changed by setting up "CORE_API_PORT" environment variable. Error handling ============== diff --git a/src/tribler-core/run_bandwidth_crawler.py b/src/tribler-core/run_bandwidth_crawler.py index 5cd0c14819..6679656dcc 100644 --- a/src/tribler-core/run_bandwidth_crawler.py +++ b/src/tribler-core/run_bandwidth_crawler.py @@ -51,7 +51,7 @@ async def start_crawler(tribler_config): if __name__ == "__main__": parser = argparse.ArgumentParser(description=('Start a crawler in the bandwidth accounting community')) parser.add_argument('--statedir', '-s', default='bw_crawler', type=str, help='Use an alternate statedir') - parser.add_argument('--restapi', '-p', default=8085, type=str, help='Use an alternate port for the REST API', + parser.add_argument('--restapi', '-p', default=52194, type=str, help='Use an alternate port for the REST API', action=PortAction, metavar='{0..65535}') args = parser.parse_args(sys.argv[1:]) diff --git a/src/tribler-core/run_tunnel_helper.py b/src/tribler-core/run_tunnel_helper.py index 620f933919..1557864ae8 100644 --- a/src/tribler-core/run_tunnel_helper.py +++ b/src/tribler-core/run_tunnel_helper.py @@ -177,7 +177,7 @@ def main(argv): parser.add_argument('--ipv8_port', '-d', default=-1, type=int, help='IPv8 port', action=PortAction, metavar='{0..65535}') parser.add_argument('--ipv8_address', '-i', default='0.0.0.0', type=str, help='IPv8 listening address', action=IPAction) parser.add_argument('--ipv8_bootstrap_override', '-b', default=None, type=str, help='Force the usage of specific IPv8 bootstrap server (ip:port)', action=IPPortAction) - parser.add_argument('--restapi', '-p', default=8085, type=str, help='Use an alternate port for the REST API', action=PortAction, metavar='{0..65535}') + parser.add_argument('--restapi', '-p', default=52194, type=str, help='Use an alternate port for the REST API', action=PortAction, metavar='{0..65535}') parser.add_argument('--cert-file', '-e', help='Path to combined certificate/key file. If not given HTTP is used.') parser.add_argument('--api-key', '-k', help='API key to use. If not given API key protection is disabled.') parser.add_argument('--random_slots', '-r', default=10, type=int, help='Specifies the number of random slots') diff --git a/src/tribler-core/tribler_core/restapi/events_endpoint.py b/src/tribler-core/tribler_core/restapi/events_endpoint.py index 219b2d925e..1c008d9718 100644 --- a/src/tribler-core/tribler_core/restapi/events_endpoint.py +++ b/src/tribler-core/tribler_core/restapi/events_endpoint.py @@ -145,7 +145,7 @@ async def get_events(self, request): .. sourcecode:: none - curl -X GET http://localhost:8085/events + curl -X GET http://localhost:52194/events """ # Setting content-type to text/event-stream to ensure browsers will handle the content properly diff --git a/src/tribler-gui/tribler_gui/core_manager.py b/src/tribler-gui/tribler_gui/core_manager.py index 45c9f7f2cf..78473b71f6 100644 --- a/src/tribler-gui/tribler_gui/core_manager.py +++ b/src/tribler-gui/tribler_gui/core_manager.py @@ -84,7 +84,7 @@ def on_core_finished(self, exit_code, exit_status): def start(self, core_args=None, core_env=None): """ - First test whether we already have a Tribler process listening on port 8085. If so, use that one and don't + First test whether we already have a Tribler process listening on port . If so, use that one and don't start a new, fresh session. """ From cb1a8c0e8316af8e1c1d9c18781649fa43986b7e Mon Sep 17 00:00:00 2001 From: drew2a Date: Wed, 3 Feb 2021 12:12:45 +0100 Subject: [PATCH 5/5] Flake&Lint --- src/tribler-core/run_tunnel_helper.py | 8 +++++--- src/tribler-gui/tribler_gui/core_manager.py | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tribler-core/run_tunnel_helper.py b/src/tribler-core/run_tunnel_helper.py index 1557864ae8..8777711152 100644 --- a/src/tribler-core/run_tunnel_helper.py +++ b/src/tribler-core/run_tunnel_helper.py @@ -72,7 +72,7 @@ def on_circuit_reject(self, reject_time, balance): def tribler_started(self): async def signal_handler(sig): - print(f"Received shut down signal {sig}") + print(f"Received shut down signal {sig}") # noqa: T001 if not self._stopping: self._stopping = True await self.session.shutdown() @@ -176,8 +176,10 @@ def main(argv): parser.add_argument('--help', '-h', action='help', default=argparse.SUPPRESS, help='Show this help message and exit') parser.add_argument('--ipv8_port', '-d', default=-1, type=int, help='IPv8 port', action=PortAction, metavar='{0..65535}') parser.add_argument('--ipv8_address', '-i', default='0.0.0.0', type=str, help='IPv8 listening address', action=IPAction) - parser.add_argument('--ipv8_bootstrap_override', '-b', default=None, type=str, help='Force the usage of specific IPv8 bootstrap server (ip:port)', action=IPPortAction) - parser.add_argument('--restapi', '-p', default=52194, type=str, help='Use an alternate port for the REST API', action=PortAction, metavar='{0..65535}') + parser.add_argument('--ipv8_bootstrap_override', '-b', default=None, type=str, + help='Force the usage of specific IPv8 bootstrap server (ip:port)', action=IPPortAction) + parser.add_argument('--restapi', '-p', default=52194, type=str, + help='Use an alternate port for the REST API', action=PortAction, metavar='{0..65535}') parser.add_argument('--cert-file', '-e', help='Path to combined certificate/key file. If not given HTTP is used.') parser.add_argument('--api-key', '-k', help='API key to use. If not given API key protection is disabled.') parser.add_argument('--random_slots', '-r', default=10, type=int, help='Specifies the number of random slots') diff --git a/src/tribler-gui/tribler_gui/core_manager.py b/src/tribler-gui/tribler_gui/core_manager.py index 78473b71f6..d81888e0e3 100644 --- a/src/tribler-gui/tribler_gui/core_manager.py +++ b/src/tribler-gui/tribler_gui/core_manager.py @@ -60,7 +60,7 @@ def on_core_read_ready(self): if b'Traceback' in raw_output: self.core_traceback = decoded_output self.core_traceback_timestamp = int(round(time.time() * 1000)) - print(decoded_output.strip()) + print(decoded_output.strip()) # noqa: T001 def on_core_finished(self, exit_code, exit_status): if self.shutting_down and self.should_stop_on_shutdown: @@ -84,8 +84,8 @@ def on_core_finished(self, exit_code, exit_status): def start(self, core_args=None, core_env=None): """ - First test whether we already have a Tribler process listening on port . If so, use that one and don't - start a new, fresh session. + First test whether we already have a Tribler process listening on port . + If so, use that one and don't start a new, fresh session. """ def on_request_error(_):