src/modules/misc.py
changeset 386 5cd680466abe
parent 384 9d4746e5dd3e
child 388 5a08791fb814
--- a/src/modules/misc.py	Thu May 15 17:04:20 2008 -0500
+++ b/src/modules/misc.py	Mon Jun 09 17:18:47 2008 -0500
@@ -24,14 +24,15 @@
 # Use is subject to license terms.
 
 import errno
+import httplib
 import os
+import platform
+import re
+import sha
+import socket
 import urllib
 import urllib2
 import urlparse
-import httplib
-import platform
-import re
-import sha
 import sys
 import zlib
 
@@ -108,7 +109,8 @@
                 try:
                         c = url_opener(req)
                 except urllib2.HTTPError, e:
-                        if e.code != httplib.NOT_FOUND or e.msg != "Version not supported":
+                        if e.code != httplib.NOT_FOUND or \
+                            e.msg != "Version not supported":
                                 raise
                         continue
                 # XXX catch BadStatusLine and convert to INTERNAL_SERVER_ERROR?
@@ -251,3 +253,58 @@
                         raise PipeError, e
                 raise
 
+
+def port_available(host, port):
+        """Returns True if the indicated port is available to bind to; otherwise
+        returns False."""
+
+        port = int(port)
+        if host is None:
+                # None is the same as INADDR_ANY, which for our purposes, should
+                # be the hostname.
+                host = socket.gethostname()
+
+        try:
+                # Get the address family of our host (to allow for IPV6, etc.).
+                for entry in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
+                    socket.SOCK_STREAM):
+                        family, socktype, proto, canonname, sockaddr = entry
+
+                        # First try to bind to the specified port to see if we
+                        # have an access problem or some other issue.
+                        sock = socket.socket(family, socktype, proto)
+                        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,
+                            1)
+                        sock.bind((host, port))
+                        sock.close()
+
+                        # Now try to connect to the specified port to see if it
+                        # is already in use.
+                        sock = socket.socket(family, socktype, proto)
+
+                        # Some systems timeout rather than refuse a connection.
+                        # This avoids getting stuck on SYN_SENT for those
+                        # systems (such as certain firewalls).
+                        sock.settimeout(1.0)
+
+                        sock.connect((host, port))
+                        sock.close()
+                        sock = None
+
+                        # If we successfully connected...
+                        raise socket.error(errno.EBUSY,
+                            'Port already in use')
+
+        except socket.error, e:
+                errnum, msg = e
+
+                if sock:
+                        sock.close()
+
+                if errnum == errno.ECONNREFUSED:
+                        # If we could not connect to the port, we know it isn't
+                        # in use.
+                        return True, None
+
+                return False, msg
+