Changes in / [d85a75d:b088380] in trunk
- Location:
- src/allmydata
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
src/allmydata/test/test_iputil.py
rd85a75d rb088380 1 1 2 import re 2 import re, errno, subprocess, os 3 3 4 from twisted.trial import unittest 5 4 6 from allmydata.util import iputil 5 7 import allmydata.test.common_util as testutil 6 8 9 10 class Namespace: 11 pass 12 7 13 DOTTED_QUAD_RE=re.compile("^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$") 14 15 MOCK_IPADDR_OUTPUT = """\ 16 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN \n\ 17 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 18 inet 127.0.0.1/8 scope host lo 19 inet6 ::1/128 scope host \n\ 20 valid_lft forever preferred_lft forever 21 2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 22 link/ether d4:3d:7e:01:b4:3e brd ff:ff:ff:ff:ff:ff 23 inet 192.168.0.6/24 brd 192.168.0.255 scope global eth1 24 inet6 fe80::d63d:7eff:fe01:b43e/64 scope link \n\ 25 valid_lft forever preferred_lft forever 26 3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 27 link/ether 90:f6:52:27:15:0a brd ff:ff:ff:ff:ff:ff 28 inet 192.168.0.2/24 brd 192.168.0.255 scope global wlan0 29 inet6 fe80::92f6:52ff:fe27:150a/64 scope link \n\ 30 valid_lft forever preferred_lft forever 31 """ 32 33 MOCK_IFCONFIG_OUTPUT = """\ 34 eth1 Link encap:Ethernet HWaddr d4:3d:7e:01:b4:3e \n\ 35 inet addr:192.168.0.6 Bcast:192.168.0.255 Mask:255.255.255.0 36 inet6 addr: fe80::d63d:7eff:fe01:b43e/64 Scope:Link 37 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 38 RX packets:154242234 errors:0 dropped:0 overruns:0 frame:0 39 TX packets:155461891 errors:0 dropped:0 overruns:0 carrier:0 40 collisions:0 txqueuelen:1000 \n\ 41 RX bytes:84367213640 (78.5 GiB) TX bytes:73401695329 (68.3 GiB) 42 Interrupt:20 Memory:f4f00000-f4f20000 \n\ 43 44 lo Link encap:Local Loopback \n\ 45 inet addr:127.0.0.1 Mask:255.0.0.0 46 inet6 addr: ::1/128 Scope:Host 47 UP LOOPBACK RUNNING MTU:16436 Metric:1 48 RX packets:27449267 errors:0 dropped:0 overruns:0 frame:0 49 TX packets:27449267 errors:0 dropped:0 overruns:0 carrier:0 50 collisions:0 txqueuelen:0 \n\ 51 RX bytes:192643017823 (179.4 GiB) TX bytes:192643017823 (179.4 GiB) 52 53 wlan0 Link encap:Ethernet HWaddr 90:f6:52:27:15:0a \n\ 54 inet addr:192.168.0.2 Bcast:192.168.0.255 Mask:255.255.255.0 55 inet6 addr: fe80::92f6:52ff:fe27:150a/64 Scope:Link 56 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 57 RX packets:12352750 errors:0 dropped:0 overruns:0 frame:0 58 TX packets:4501451 errors:0 dropped:0 overruns:0 carrier:0 59 collisions:0 txqueuelen:1000 \n\ 60 RX bytes:3916475942 (3.6 GiB) TX bytes:458353654 (437.1 MiB) 61 """ 62 63 # This is actually from a VirtualBox VM running XP. 64 MOCK_ROUTE_OUTPUT = """\ 65 =========================================================================== 66 Interface List 67 0x1 ........................... MS TCP Loopback interface 68 0x2 ...08 00 27 c3 80 ad ...... AMD PCNET Family PCI Ethernet Adapter - Packet Scheduler Miniport 69 =========================================================================== 70 =========================================================================== 71 Active Routes: 72 Network Destination Netmask Gateway Interface Metric 73 0.0.0.0 0.0.0.0 10.0.2.2 10.0.2.15 20 74 10.0.2.0 255.255.255.0 10.0.2.15 10.0.2.15 20 75 10.0.2.15 255.255.255.255 127.0.0.1 127.0.0.1 20 76 10.255.255.255 255.255.255.255 10.0.2.15 10.0.2.15 20 77 127.0.0.0 255.0.0.0 127.0.0.1 127.0.0.1 1 78 224.0.0.0 240.0.0.0 10.0.2.15 10.0.2.15 20 79 255.255.255.255 255.255.255.255 10.0.2.15 10.0.2.15 1 80 Default Gateway: 10.0.2.2 81 =========================================================================== 82 Persistent Routes: 83 None 84 """ 85 86 UNIX_TEST_ADDRESSES = set(["127.0.0.1", "192.168.0.6", "192.168.0.2", "192.168.0.10"]) 87 WINDOWS_TEST_ADDRESSES = set(["127.0.0.1", "10.0.2.15", "192.168.0.10"]) 88 CYGWIN_TEST_ADDRESSES = set(["127.0.0.1", "192.168.0.10"]) 89 90 91 class FakeProcess: 92 def __init__(self, output, err): 93 self.output = output 94 self.err = err 95 def communicate(self): 96 return (self.output, self.err) 97 8 98 9 99 class ListAddresses(testutil.SignalMixin, unittest.TestCase): … … 15 105 d = iputil.get_local_addresses_async() 16 106 def _check(addresses): 17 self.failUnless(len(addresses) >= 1) # always have localhost 18 self.failUnless("127.0.0.1" in addresses, addresses) 19 self.failIf("0.0.0.0" in addresses, addresses) 107 self.failUnlessIn("127.0.0.1", addresses) 108 self.failIfIn("0.0.0.0", addresses) 20 109 d.addCallbacks(_check) 21 110 return d 22 111 # David A.'s OpenSolaris box timed out on this test one time when it was at 2s. 23 112 test_list_async.timeout=4 113 114 def _test_list_async_mock(self, command, output, expected): 115 ns = Namespace() 116 ns.first = True 117 118 def call_Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, 119 preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, 120 universal_newlines=False, startupinfo=None, creationflags=0): 121 if ns.first: 122 ns.first = False 123 e = OSError("EINTR") 124 e.errno = errno.EINTR 125 raise e 126 elif os.path.basename(args[0]) == command: 127 return FakeProcess(output, "") 128 else: 129 e = OSError("[Errno 2] No such file or directory") 130 e.errno = errno.ENOENT 131 raise e 132 self.patch(subprocess, 'Popen', call_Popen) 133 134 def call_get_local_ip_for(target): 135 if target in ("localhost", "127.0.0.1"): 136 return "127.0.0.1" 137 else: 138 return "192.168.0.10" 139 self.patch(iputil, 'get_local_ip_for', call_get_local_ip_for) 140 141 def call_which(name): 142 return [name] 143 self.patch(iputil, 'which', call_which) 144 145 d = iputil.get_local_addresses_async() 146 def _check(addresses): 147 self.failUnlessEquals(set(addresses), set(expected)) 148 d.addCallbacks(_check) 149 return d 150 151 def test_list_async_mock_ip_addr(self): 152 self.patch(iputil, 'platform', "linux2") 153 return self._test_list_async_mock("ip", MOCK_IPADDR_OUTPUT, UNIX_TEST_ADDRESSES) 154 155 def test_list_async_mock_ifconfig(self): 156 self.patch(iputil, 'platform', "linux2") 157 return self._test_list_async_mock("ifconfig", MOCK_IFCONFIG_OUTPUT, UNIX_TEST_ADDRESSES) 158 159 def test_list_async_mock_route(self): 160 self.patch(iputil, 'platform', "win32") 161 return self._test_list_async_mock("route.exe", MOCK_ROUTE_OUTPUT, WINDOWS_TEST_ADDRESSES) 162 163 def test_list_async_mock_cygwin(self): 164 self.patch(iputil, 'platform', "cygwin") 165 return self._test_list_async_mock(None, None, CYGWIN_TEST_ADDRESSES) -
src/allmydata/util/iputil.py
rd85a75d rb088380 1 1 # from the Python Standard Library 2 import os, re, socket, sys, subprocess 2 import os, re, socket, subprocess, errno 3 4 from sys import platform 3 5 4 6 # from Twisted … … 82 84 addresses = [] 83 85 local_ip = get_local_ip_for(target) 84 if local_ip :86 if local_ip is not None: 85 87 addresses.append(local_ip) 86 88 87 if sys.platform == "cygwin":88 d = _cygwin_hack_find_addresses( target)89 if platform == "cygwin": 90 d = _cygwin_hack_find_addresses() 89 91 else: 90 92 d = _find_addresses_via_config() … … 132 134 # no route to that host 133 135 localip = None 134 port.stopListening() # note, this returns a Deferred 136 d = port.stopListening() 137 d.addErrback(log.err) 135 138 return localip 136 139 137 # k: result of sys.platform, v: which kind of IP configuration reader we use138 _platform_map = {139 "linux-i386": "linux", # redhat140 "linux-ppc": "linux", # redhat141 "linux2": "linux", # debian142 "linux3": "linux", # debian143 "win32": "win32",144 "irix6-n32": "irix",145 "irix6-n64": "irix",146 "irix6": "irix",147 "openbsd2": "bsd",148 "openbsd3": "bsd",149 "openbsd4": "bsd",150 "openbsd5": "bsd",151 "darwin": "bsd", # Mac OS X152 "freebsd4": "bsd",153 "freebsd5": "bsd",154 "freebsd6": "bsd",155 "freebsd7": "bsd",156 "freebsd8": "bsd",157 "freebsd9": "bsd",158 "netbsd1": "bsd",159 "netbsd2": "bsd",160 "netbsd3": "bsd",161 "netbsd4": "bsd",162 "netbsd5": "bsd",163 "netbsd6": "bsd",164 "sunos5": "sunos",165 "cygwin": "cygwin",166 }167 168 class UnsupportedPlatformError(Exception):169 pass170 140 171 141 # Wow, I'm really amazed at home much mileage we've gotten out of calling … … 173 143 # versions so far. Still, the real system calls would much be preferred... 174 144 # ... thus wrote Greg Smith in time immemorial... 175 _win32_path = 'route.exe' 176 _win32_args = ('print',) 177 _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) 178 179 # These work in Redhat 6.x and Debian 2.2 potato 180 _linux_path = '/sbin/ifconfig' 181 _linux_re = re.compile('^\s*inet [a-zA-Z]*:?(?P<address>\d+\.\d+\.\d+\.\d+)\s.+$', flags=re.M|re.I|re.S) 182 183 # NetBSD 1.4 (submitted by Rhialto), Darwin, Mac OS X 184 _netbsd_path = '/sbin/ifconfig' 185 _netbsd_args = ('-a',) 186 _netbsd_re = re.compile('^\s+inet [a-zA-Z]*:?(?P<address>\d+\.\d+\.\d+\.\d+)\s.+$', flags=re.M|re.I|re.S) 187 188 # Irix 6.5 189 _irix_path = '/usr/etc/ifconfig' 190 191 # Solaris 2.x 192 _sunos_path = '/usr/sbin/ifconfig' 193 194 195 # k: platform string as provided in the value of _platform_map 196 # v: tuple of (path_to_tool, args, regex,) 197 _tool_map = { 198 "linux": (_linux_path, (), _linux_re,), 199 "win32": (_win32_path, _win32_args, _win32_re,), 200 "cygwin": (_win32_path, _win32_args, _win32_re,), 201 "bsd": (_netbsd_path, _netbsd_args, _netbsd_re,), 202 "irix": (_irix_path, _netbsd_args, _netbsd_re,), 203 "sunos": (_sunos_path, _netbsd_args, _netbsd_re,), 204 } 145 _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) 146 _win32_commands = (('route.exe', ('print',), _win32_re),) 147 148 # These work in most Unices. 149 _addr_re = re.compile(r'^\s*inet [a-zA-Z]*:?(?P<address>\d+\.\d+\.\d+\.\d+)[\s/].+$', flags=re.M|re.I|re.S) 150 _unix_commands = (('/bin/ip', ('addr',), _addr_re), 151 ('/sbin/ifconfig', ('-a',), _addr_re), 152 ('/usr/sbin/ifconfig', ('-a',), _addr_re), 153 ('/usr/etc/ifconfig', ('-a',), _addr_re), 154 ('ifconfig', ('-a',), _addr_re), 155 ('/sbin/ifconfig', (), _addr_re), 156 ) 157 205 158 206 159 def _find_addresses_via_config(): … … 208 161 209 162 def _synchronously_find_addresses_via_config(): 210 # originally by Greg Smith, hacked by Zooko to conform to Brian's API 211 212 platform = _platform_map.get(sys.platform) 213 if not platform: 214 raise UnsupportedPlatformError(sys.platform) 215 216 (pathtotool, args, regex,) = _tool_map[platform] 217 218 # If pathtotool is a fully qualified path then we just try that. 219 # If it is merely an executable name then we use Twisted's 220 # "which()" utility and try each executable in turn until one 221 # gives us something that resembles a dotted-quad IPv4 address. 222 223 if os.path.isabs(pathtotool): 224 return _query(pathtotool, args, regex) 163 # originally by Greg Smith, hacked by Zooko and then Daira 164 165 # We don't reach here for cygwin. 166 if platform == 'win32': 167 commands = _win32_commands 225 168 else: 226 exes_to_try = which(pathtotool) 169 commands = _unix_commands 170 171 for (pathtotool, args, regex) in commands: 172 # If pathtotool is a fully qualified path then we just try that. 173 # If it is merely an executable name then we use Twisted's 174 # "which()" utility and try each executable in turn until one 175 # gives us something that resembles a dotted-quad IPv4 address. 176 177 if os.path.isabs(pathtotool): 178 exes_to_try = [pathtotool] 179 else: 180 exes_to_try = which(pathtotool) 181 227 182 for exe in exes_to_try: 228 183 try: … … 232 187 if addresses: 233 188 return addresses 234 return [] 189 190 return [] 235 191 236 192 def _query(path, args, regex): 237 193 env = {'LANG': 'en_US.UTF-8'} 238 p = subprocess.Popen([path] + list(args), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) 239 (output, err) = p.communicate() 194 TRIES = 5 195 for trial in xrange(TRIES): 196 try: 197 p = subprocess.Popen([path] + list(args), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) 198 (output, err) = p.communicate() 199 break 200 except OSError, e: 201 if e.errno == errno.EINTR and trial < TRIES-1: 202 continue 203 raise 240 204 241 205 addresses = [] … … 244 208 m = regex.match(outline) 245 209 if m: 246 addr = m.group dict()['address']210 addr = m.group('address') 247 211 if addr not in addresses: 248 212 addresses.append(addr) … … 250 214 return addresses 251 215 252 def _cygwin_hack_find_addresses( target):216 def _cygwin_hack_find_addresses(): 253 217 addresses = [] 254 for h in [target, "localhost", "127.0.0.1",]: 255 try: 256 addr = get_local_ip_for(h) 257 if addr not in addresses: 258 addresses.append(addr) 259 except socket.gaierror: 260 pass 218 for h in ["localhost", "127.0.0.1",]: 219 addr = get_local_ip_for(h) 220 if addr is not None and addr not in addresses: 221 addresses.append(addr) 261 222 262 223 return defer.succeed(addresses)
Note: See TracChangeset
for help on using the changeset viewer.