From d5611a80c3b042036478ecbd67e6cb8265baf9bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Doktor?= Date: Wed, 5 Dec 2018 15:24:04 +0100 Subject: [PATCH] utils.network: Also check for UDP protocols in is_port_free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Binding port won't complain when port already opened for UDP packets and we are trying to bind it for TCP packets. Let's do a combination. Note I also tried: tuple(getattr(socket, _) for _ in dir(socket) if _.startswith('SOCK_') to cover all of the protocols, but all the time they just reported incorrect combination so let's just stick with the most common ones. Signed-off-by: Lukáš Doktor --- avocado/utils/network.py | 34 ++++++++++++++++--------- selftests/unit/test_utils_network.py | 37 +++++++++++++++------------- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/avocado/utils/network.py b/avocado/utils/network.py index 0385c5e0..cd8d97ce 100644 --- a/avocado/utils/network.py +++ b/avocado/utils/network.py @@ -25,31 +25,41 @@ from .data_structures import Borg #: Families taken into account in this class FAMILIES = (socket.AF_INET, socket.AF_INET6) +#: Protocols taken into account in this class +PROTOCOLS = (socket.SOCK_STREAM, socket.SOCK_DGRAM) def is_port_free(port, address): """ Return True if the given port is available for use. - Currently we only check for TCP connections on IPv4/6 + Currently we only check for TCP/UDP connections on IPv4/6 :param port: Port number :param address: Socket address to bind or connect """ s = None + if address == "localhost": + protocols = PROTOCOLS + else: + # sock.connect always connects for UDP + protocols = (socket.SOCK_STREAM, ) try: for family in FAMILIES: - try: - s = socket.socket(family, socket.SOCK_STREAM) - if address == "localhost": - s.bind((address, port)) - else: - s.connect((address, port)) - return False - except socket.error: - if address == "localhost": - return False - s.close() + for protocol in protocols: + try: + s = socket.socket(family, protocol) + if address == "localhost": + s.bind((address, port)) + else: + s.connect((address, port)) + return False + except socket.error as exc: + if exc.errno in (93, 94): # Unsupported combinations + continue + if address == "localhost": + return False + s.close() return True finally: if s is not None: diff --git a/selftests/unit/test_utils_network.py b/selftests/unit/test_utils_network.py index 669cdbd2..3c41baae 100644 --- a/selftests/unit/test_utils_network.py +++ b/selftests/unit/test_utils_network.py @@ -55,23 +55,26 @@ class FreePort(unittest.TestCase): else: addrs = ipv6_addrs for addr in addrs: - try: - sock = socket.socket(family, socket.SOCK_STREAM) - sock.bind((addr, port)) - if network.is_port_free(port, "localhost"): - bad.append("%s, %s: reports free" % (family, addr)) - else: - good.append("%s, %s" % (family, addr)) - except Exception as exc: - if getattr(exc, 'errno', None) in (-2, 2, 22, 94): - skip.append("%s, %s: Not supported: %s" - % (family, addr, exc)) - else: - bad.append("%s, %s: Failed to bind: %s" - % (family, addr, exc)) - finally: - if sock is not None: - sock.close() + for protocol in network.PROTOCOLS: + try: + sock = socket.socket(family, protocol) + sock.bind((addr, port)) + if network.is_port_free(port, "localhost"): + bad.append("%s, %s, %s: reports free" + % (family, protocol, addr)) + else: + good.append("%s, %s, %s" % (family, protocol, + addr)) + except Exception as exc: + if getattr(exc, 'errno', None) in (-2, 2, 22, 94): + skip.append("%s, %s, %s: Not supported: %s" + % (family, protocol, addr, exc)) + else: + bad.append("%s, %s, %s: Failed to bind: %s" + % (family, protocol, addr, exc)) + finally: + if sock is not None: + sock.close() self.assertFalse(bad, "Following combinations failed:\n%s\n\n" "Following combinations passed:\n%s\n\n" "Following combinations were skipped:\n%s" -- GitLab