Home | History | Annotate | Download | only in utils_lib
      1 #   Copyright 2016 - The Android Open Source Project
      2 #
      3 #   Licensed under the Apache License, Version 2.0 (the "License");
      4 #   you may not use this file except in compliance with the License.
      5 #   You may obtain a copy of the License at
      6 #
      7 #       http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 #   Unless required by applicable law or agreed to in writing, software
     10 #   distributed under the License is distributed on an "AS IS" BASIS,
     11 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 #   See the License for the specific language governing permissions and
     13 #   limitations under the License.
     14 
     15 import socket
     16 
     17 
     18 def get_available_host_port():
     19     """Finds a semi-random available port.
     20 
     21     A race condition is still possible after the port number is returned, if
     22     another process happens to bind it.
     23 
     24     Returns:
     25         A port number that is unused on both TCP and UDP.
     26     """
     27     # On the 2.6 kernel, calling _try_bind() on UDP socket returns the
     28     # same port over and over. So always try TCP first.
     29     while True:
     30         # Ask the OS for an unused port.
     31         port = _try_bind(0, socket.SOCK_STREAM, socket.IPPROTO_TCP)
     32         # Check if this port is unused on the other protocol.
     33         if port and _try_bind(port, socket.SOCK_DGRAM, socket.IPPROTO_UDP):
     34             return port
     35 
     36 
     37 def is_port_available(port):
     38     """Checks if a given port number is available on the system.
     39 
     40     Args:
     41         port: An integer which is the port number to check.
     42 
     43     Returns:
     44         True if the port is available; False otherwise.
     45     """
     46     return (_try_bind(port, socket.SOCK_STREAM, socket.IPPROTO_TCP) and
     47             _try_bind(port, socket.SOCK_DGRAM, socket.IPPROTO_UDP))
     48 
     49 
     50 def _try_bind(port, socket_type, socket_proto):
     51     s = socket.socket(socket.AF_INET, socket_type, socket_proto)
     52     try:
     53         try:
     54             s.bind(('', port))
     55             # The result of getsockname() is protocol dependent, but for both
     56             # IPv4 and IPv6 the second field is a port number.
     57             return s.getsockname()[1]
     58         except socket.error:
     59             return None
     60     finally:
     61         s.close()
     62