Example #1
0
def _get_available_port(queue):
    """
    Get the next available port from the port queue and return it.

    Since there can be a delay between when the queue is populated and when the
    port is requested, this checks the next port in the queue to see whether it
    is still not open. If it isn't, it is dropped from the queue and the next
    one is inspected. This process continues until either an available port is
    found, or, if the queue is exhausted, PortQueueSelectionError is raised.

    Returns:
        An available (i.e., non-open) port.

    Throws:
        PortQueueSelectionError if the port queue is exhausted.
    """

    if queue.qsize() == 0:
        host.WriteWarning("Port queue is empty.")
        raise PortQueueSelectionError(
            "Could not get a valid port because the queue is empty")

    port = queue.get()
    while PortOpen(port):
        host.WriteDebug('_get_available_port'
                        "Port was open but now is used: {}".format(port))
        if queue.qsize() == 0:
            host.WriteWarning("Port queue is empty.")
            raise PortQueueSelectionError(
                "Could not get a valid port because the queue is empty")
        port = queue.get()
    return port
Example #2
0
def PortOpen(port, address=None):
    """
    Detect whether the port is open, that is a socket is currently using that port.

    Open ports are currently in use by an open socket and are therefore not available
    for a server to listen on them.

    Returns:
        True if there is a connection currently listening on the port, False if
        there is no server listening on the port currently.
    """
    ret = True
    if address is None:
        address = "localhost"

    address = (address, port)

    try:
        # Try to connect on that port. If we can connect on it, then someone is
        # listening on that port and therefore the port is open and not usable
        # by another application.
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            sock.bind(address)
            # Bind succeeded.
            host.WriteDebug(
                'PortOpen',
                f"Bind on port {port} succeeded, the port is closed "
                "(no application is listening on it) "
                "and thus a future connection can use it")
            ret = False

    except socket.error:
        host.WriteDebug(
            'PortOpen', f"socket error binding on port {port}. "
            "Assume a future connection cannot use it")
    except socket.timeout:
        host.WriteDebug(
            'PortOpen', f"Timeout error binding on port {port}. "
            "Assume a future connection cannot use it")

    return ret
Example #3
0
def PortOpen(port, address=None):
    """
    Detect whether the port is open, that is a socket is currently using that port.

    Open ports are currently in use by an open socket and are therefore not available
    for a server to listen on them.

    Returns:
        True if there is a connection currently listening on the port, False if
        there is no server listening on the port currently.
    """
    ret = False
    if address is None:
        address = "localhost"

    address = (address, port)

    try:
        # Try to connect on that port. If we can connect on it, then someone is
        # listening on that port and therefore the port is open.
        s = socket.create_connection(address, timeout=.5)
        s.close()
        ret = True
        host.WriteDebug(
            'PortOpen', "Connection to port {} succeeded, the port is open, "
            "and a future connection cannot use it".format(port))
    except socket.error:
        s = None
        host.WriteDebug(
            'PortOpen', "socket error for port {0}, port is closed, "
            "and therefore a future connection can use it".format(port))
    except socket.timeout:
        s = None
        host.WriteDebug(
            'PortOpen', "Timeout error for port {0}, port is closed, "
            "and therefore a future connection can use it".format(port))

    return ret
Example #4
0
def _setup_port_queue(amount=1000):
    """
    Build up the set of ports that the OS in theory will not use.
    """
    global g_ports
    if g_ports is None:
        host.WriteDebug('_setup_port_queue', "Populating the port queue.")
        g_ports = Queue.Queue()
    else:
        # The queue has already been populated.
        host.WriteDebug(
            '_setup_port_queue',
            "Queue was previously populated. Queue size: {}".format(
                g_ports.qsize()))
        return
    try:
        # Use sysctl to find the range of ports that the OS publishes it uses.
        # some docker setups don't have sbin setup correctly
        new_env = os.environ.copy()
        new_env['PATH'] = "/sbin:/usr/sbin:" + new_env['PATH']
        if 'Darwin' == platform.system():
            dmin = subprocess.check_output(
                ["sysctl", "net.inet.ip.portrange.first"],
                env=new_env).decode().split(":")[1].split()[0]
            dmax = subprocess.check_output(
                ["sysctl", "net.inet.ip.portrange.last"],
                env=new_env).decode().split(":")[1].split()[0]
        else:
            dmin, dmax = subprocess.check_output(
                ["sysctl", "net.ipv4.ip_local_port_range"],
                env=new_env).decode().split("=")[1].split()
        dmin = int(dmin)
        dmax = int(dmax)
    except Exception:
        host.WriteWarning(
            "Unable to call sysctrl!\n Tests may fail because of bad port selection!"
        )
        return

    rmin = dmin - 2000
    rmax = 65536 - dmax

    if rmax > amount:
        # Fill in ports, starting above the upper OS-usable port range.
        port = dmax + 1
        while port < 65536 and g_ports.qsize() < amount:
            if not PortOpen(port):
                host.WriteDebug(
                    '_setup_port_queue',
                    "Adding a possible port to connect to: {0}".format(port))
                g_ports.put(port)
            else:
                host.WriteDebug(
                    '_setup_port_queue',
                    "Rejecting a possible port to connect to: {0}".format(
                        port))
            port += 1
    if rmin > amount and g_ports.qsize() < amount:
        port = 2001
        # Fill in more ports, starting at 2001, well above well known ports,
        # and going up until the minimum port range used by the OS.
        while port < dmin and g_ports.qsize() < amount:
            if not PortOpen(port):
                host.WriteDebug(
                    '_setup_port_queue',
                    "Adding a possible port to connect to: {0}".format(port))
                g_ports.put(port)
            else:
                host.WriteDebug(
                    '_setup_port_queue',
                    "Rejecting a possible port to connect to: {0}".format(
                        port))
            port += 1