diff --git a/avocado/utils/network.py b/avocado/utils/network.py index 0385c5e02099a368d908652de63000d418772af3..cd8d97ce4520cfb6d2b08d717876f62bec97f0e7 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 669cdbd22e653b4617e74f8cba3d039fb405437b..3c41baae15cbd3341e792e7a854d4a8426f30067 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"