@@ -78,19 +78,41 @@ def _can_bind_at_port(
7878 return True
7979
8080
81- def is_process_on_port (port : int ) -> bool :
81+ def _can_bind_at_any_port (address_family : socket .AddressFamily | int ) -> bool :
82+ """Check if any port is available for binding.
83+
84+ Args:
85+ address_family: The address family (e.g., socket.AF_INET or socket.AF_INET6).
86+
87+ Returns:
88+ Whether any port is available for binding.
89+ """
90+ with closing (socket .socket (address_family , socket .SOCK_STREAM )) as sock :
91+ try :
92+ sock .bind (("" , 0 )) # Bind to any available port
93+ except (OverflowError , PermissionError , OSError ) as e :
94+ console .debug (f"Unable to bind to any port for { address_family } : { e } " )
95+ return False
96+ return True
97+
98+
99+ def is_process_on_port (
100+ port : int ,
101+ address_families : Sequence [socket .AddressFamily | int ] = (
102+ socket .AF_INET ,
103+ socket .AF_INET6 ,
104+ ),
105+ ) -> bool :
82106 """Check if a process is running on the given port.
83107
84108 Args:
85109 port: The port.
110+ address_families: The address families to check (default: IPv4 and IPv6).
86111
87112 Returns:
88113 Whether a process is running on the given port.
89114 """
90- return (
91- not _can_bind_at_port (socket .AF_INET , "" , port ) # Test IPv4 local network
92- or not _can_bind_at_port (socket .AF_INET6 , "" , port ) # Test IPv6 local network
93- )
115+ return any (not _can_bind_at_port (family , "" , port ) for family in address_families )
94116
95117
96118MAXIMUM_PORT = 2 ** 16 - 1
@@ -113,13 +135,30 @@ def handle_port(service_name: str, port: int, auto_increment: bool) -> int:
113135 """
114136 console .debug (f"Checking if { service_name .capitalize ()} port: { port } is in use." )
115137
116- if not is_process_on_port (port ):
138+ families = [
139+ address_family
140+ for address_family in (socket .AF_INET , socket .AF_INET6 )
141+ if _can_bind_at_any_port (address_family )
142+ ]
143+
144+ if not families :
145+ console .error (
146+ f"Unable to bind to any port for { service_name } . "
147+ "Please check your network configuration."
148+ )
149+ raise click .exceptions .Exit (1 )
150+
151+ console .debug (
152+ f"Checking if { service_name .capitalize ()} port: { port } is in use for families: { families } ."
153+ )
154+
155+ if not is_process_on_port (port , families ):
117156 console .debug (f"{ service_name .capitalize ()} port: { port } is not in use." )
118157 return port
119158
120159 if auto_increment :
121160 for new_port in range (port + 1 , MAXIMUM_PORT + 1 ):
122- if not is_process_on_port (new_port ):
161+ if not is_process_on_port (new_port , families ):
123162 console .info (
124163 f"The { service_name } will run on port [bold underline]{ new_port } [/bold underline]."
125164 )
0 commit comments