3021: Use bind(0.0.0.0, 0) instead of grep /proc/net/tcp to find a port number.
authorTom Clegg <tom@curoverse.com>
Fri, 6 Feb 2015 17:46:57 +0000 (12:46 -0500)
committerTom Clegg <tom@curoverse.com>
Fri, 6 Feb 2015 17:46:57 +0000 (12:46 -0500)
sdk/python/tests/run_test_server.py

index dce1e73ef7dd13223ff1b22392fba7a2c2c2f4ea..5fee9eb0ec193d0cd4c3496480bf8b103727ea80 100644 (file)
@@ -9,6 +9,7 @@ import random
 import re
 import shutil
 import signal
+import socket
 import subprocess
 import string
 import sys
@@ -94,28 +95,22 @@ def kill_server_pid(pidfile, wait=10, passenger_root=False):
         pass
 
 def find_available_port():
-    """Return a port number that is not in use right now.
+    """Return an IPv4 port number that is not in use right now.
+
+    We assume whoever needs to use the returned port is able to reuse
+    a recently used port without waiting for TIME_WAIT (see
+    SO_REUSEADDR / SO_REUSEPORT).
 
     Some opportunity for races here, but it's better than choosing
     something at random and not checking at all. If all of our servers
     (hey Passenger) knew that listening on port 0 was a thing, the OS
     would take care of the races, and this wouldn't be needed at all.
     """
-    port = None
-    while port is None:
-        port = random.randint(20000, 40000)
-        port_hex = ':%04x ' % port
-        try:
-            with open('/proc/net/tcp', 'r') as f:
-                for line in f:
-                    if 0 <= string.find(line, port_hex):
-                        port = None
-                        break
-        except OSError:
-            # This isn't going so well. Just use the random port.
-            pass
-        except IOError:
-            pass
+
+    sock = socket.socket()
+    sock.bind(('0.0.0.0', 0))
+    port = sock.getsockname()[1]
+    sock.close()
     return port
 
 def run(leave_running_atexit=False):