iputil.py: refactor address-finding code to treat all Unices the same.
authorDaira Hopwood <david-sarah@jacaranda.org>
Tue, 28 May 2013 18:52:19 +0000 (19:52 +0100)
committerDaira Hopwood <david-sarah@jacaranda.org>
Tue, 28 May 2013 18:52:19 +0000 (19:52 +0100)
refs #1988, #982, #1064, #1536, #1935
fixes #898, #1707, #1918

Signed-off-by: Daira Hopwood <david-sarah@jacaranda.org>
src/allmydata/util/iputil.py

index 1c8ba3eda570a57265f93f7fb5ecb1097bb57c42..c612ffcfec1bb61fe6078eb16a83cc9725f641d2 100644 (file)
@@ -134,96 +134,48 @@ def get_local_ip_for(target):
     port.stopListening() # note, this returns a Deferred
     return localip
 
-# k: result of sys.platform, v: which kind of IP configuration reader we use
-_platform_map = {
-    "linux-i386": "linux", # redhat
-    "linux-ppc": "linux",  # redhat
-    "linux2": "linux",     # debian
-    "linux3": "linux",     # debian
-    "win32": "win32",
-    "irix6-n32": "irix",
-    "irix6-n64": "irix",
-    "irix6": "irix",
-    "openbsd2": "bsd",
-    "openbsd3": "bsd",
-    "openbsd4": "bsd",
-    "openbsd5": "bsd",
-    "darwin": "bsd",       # Mac OS X
-    "freebsd4": "bsd",
-    "freebsd5": "bsd",
-    "freebsd6": "bsd",
-    "freebsd7": "bsd",
-    "freebsd8": "bsd",
-    "freebsd9": "bsd",
-    "netbsd1": "bsd",
-    "netbsd2": "bsd",
-    "netbsd3": "bsd",
-    "netbsd4": "bsd",
-    "netbsd5": "bsd",
-    "netbsd6": "bsd",
-    "sunos5": "sunos",
-    "cygwin": "cygwin",
-    }
-
-class UnsupportedPlatformError(Exception):
-    pass
 
 # Wow, I'm really amazed at home much mileage we've gotten out of calling
 # the external route.exe program on windows...  It appears to work on all
 # versions so far.  Still, the real system calls would much be preferred...
 # ... thus wrote Greg Smith in time immemorial...
-_win32_path = 'route.exe'
-_win32_args = ('print',)
-_win32_re = re.compile('^\s*\d+\.\d+\.\d+\.\d+\s.+\s(?P<address>\d+\.\d+\.\d+\.\d+)\s+(?P<metric>\d+)\s*$', flags=re.M|re.I|re.S)
+_win32_re = re.compile(r'^\s*\d+\.\d+\.\d+\.\d+\s.+\s(?P<address>\d+\.\d+\.\d+\.\d+)\s+(?P<metric>\d+)\s*$', flags=re.M|re.I|re.S)
+_win32_commands = (('route.exe', ('print',), _win32_re),)
 
-# These work in Redhat 6.x and Debian 2.2 potato
-_linux_path = '/sbin/ifconfig'
-_linux_re = re.compile('^\s*inet [a-zA-Z]*:?(?P<address>\d+\.\d+\.\d+\.\d+)\s.+$', flags=re.M|re.I|re.S)
+# These work in most Unices.
+_addr_re = re.compile(r'^\s*inet [a-zA-Z]*:?(?P<address>\d+\.\d+\.\d+\.\d+)[\s/].+$', flags=re.M|re.I|re.S)
+_unix_commands = (('/bin/ip addr', (), _addr_re),
+                  ('/sbin/ifconfig', ('-a',), _addr_re),
+                  ('/usr/sbin/ifconfig', ('-a',), _addr_re),
+                  ('/usr/etc/ifconfig', ('-a',), _addr_re),
+                  ('ifconfig', ('-a',), _addr_re),
+                  ('/sbin/ifconfig', (), _addr_re),
+                 )
 
-# NetBSD 1.4 (submitted by Rhialto), Darwin, Mac OS X
-_netbsd_path = '/sbin/ifconfig'
-_netbsd_args = ('-a',)
-_netbsd_re = re.compile('^\s+inet [a-zA-Z]*:?(?P<address>\d+\.\d+\.\d+\.\d+)\s.+$', flags=re.M|re.I|re.S)
-
-# Irix 6.5
-_irix_path = '/usr/etc/ifconfig'
-
-# Solaris 2.x
-_sunos_path = '/usr/sbin/ifconfig'
-
-
-# k: platform string as provided in the value of _platform_map
-# v: tuple of (path_to_tool, args, regex,)
-_tool_map = {
-    "linux": (_linux_path, (), _linux_re,),
-    "win32": (_win32_path, _win32_args, _win32_re,),
-    "cygwin": (_win32_path, _win32_args, _win32_re,),
-    "bsd": (_netbsd_path, _netbsd_args, _netbsd_re,),
-    "irix": (_irix_path, _netbsd_args, _netbsd_re,),
-    "sunos": (_sunos_path, _netbsd_args, _netbsd_re,),
-    }
 
 def _find_addresses_via_config():
     return threads.deferToThread(_synchronously_find_addresses_via_config)
 
 def _synchronously_find_addresses_via_config():
-    # originally by Greg Smith, hacked by Zooko to conform to Brian's API
+    # originally by Greg Smith, hacked by Zooko and then Daira
 
-    platform = _platform_map.get(sys.platform)
-    if not platform:
-        raise UnsupportedPlatformError(sys.platform)
+    # We don't reach here for cygwin.
+    if sys.platform == 'win32':
+        commands = _win32_commands
+    else:
+        commands = _unix_commands
 
-    (pathtotool, args, regex,) = _tool_map[platform]
+    for (pathtotool, args, regex) in commands:
+        # If pathtotool is a fully qualified path then we just try that.
+        # If it is merely an executable name then we use Twisted's
+        # "which()" utility and try each executable in turn until one
+        # gives us something that resembles a dotted-quad IPv4 address.
 
-    # If pathtotool is a fully qualified path then we just try that.
-    # If it is merely an executable name then we use Twisted's
-    # "which()" utility and try each executable in turn until one
-    # gives us something that resembles a dotted-quad IPv4 address.
+        if os.path.isabs(pathtotool):
+            exes_to_try = [pathtotool]
+        else:
+            exes_to_try = which(pathtotool)
 
-    if os.path.isabs(pathtotool):
-        return _query(pathtotool, args, regex)
-    else:
-        exes_to_try = which(pathtotool)
         for exe in exes_to_try:
             try:
                 addresses = _query(exe, args, regex)
@@ -231,7 +183,8 @@ def _synchronously_find_addresses_via_config():
                 addresses = []
             if addresses:
                 return addresses
-        return []
+
+    return []
 
 def _query(path, args, regex):
     env = {'LANG': 'en_US.UTF-8'}