# HG changeset patch # User RhodeCode Admin # Date 2023-02-01 20:49:53 # Node ID 5839470880b81e5e95ed78bfb783f2ee8e570839 # Parent f20a077bd8258f085e3b3f459483b169d6d1db75 utils: by default use OS implemented pick port which is WAAAY faster, leave fallback if we need specific range. diff --git a/rhodecode/lib/utils2.py b/rhodecode/lib/utils2.py --- a/rhodecode/lib/utils2.py +++ b/rhodecode/lib/utils2.py @@ -39,6 +39,7 @@ import socket import errno import random from functools import update_wrapper, partial, wraps +from contextlib import closing import pygments.lexers import sqlalchemy @@ -1190,23 +1191,21 @@ def user_agent_normalizer(user_agent_raw return ua -def get_available_port(min_port=40000, max_port=55555): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - hostname = '127.0.0.1' - pick_port = min_port - +def get_available_port(min_port=40000, max_port=55555, use_range=False): + hostname = '' for _ in range(min_port, max_port): - pick_port = random.randint(min_port, max_port) - try: - sock.bind((hostname, pick_port)) - sock.close() - break - except OSError: - continue - except socket.error as e: - if e.args[0] in [errno.EADDRINUSE, errno.ECONNREFUSED]: + pick_port = 0 + if use_range: + pick_port = random.randint(min_port, max_port) + + with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: + try: + s.bind((hostname, pick_port)) + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + return s.getsockname()[1] + except OSError: continue - raise - - del sock - return pick_port + except socket.error as e: + if e.args[0] in [errno.EADDRINUSE, errno.ECONNREFUSED]: + continue + raise