##// END OF EJS Templates
Merge pull request #4305 from minrk/even-more-ways-to-get-ifaces...
Matthias Bussonnier -
r12911:aeeb7f5a merge
parent child Browse files
Show More
@@ -5,12 +5,14 b' LOCALHOST : The loopback interface, or the first interface that points to this'
5 machine. It will *almost* always be '127.0.0.1'
5 machine. It will *almost* always be '127.0.0.1'
6
6
7 LOCAL_IPS : A list of IP addresses, loopback first, that point to this machine.
7 LOCAL_IPS : A list of IP addresses, loopback first, that point to this machine.
8 This will include LOCALHOST, PUBLIC_IPS, and aliases for all hosts,
9 such as '0.0.0.0'.
8
10
9 PUBLIC_IPS : A list of public IP addresses that point to this machine.
11 PUBLIC_IPS : A list of public IP addresses that point to this machine.
10 Use these to tell remote clients where to find you.
12 Use these to tell remote clients where to find you.
11 """
13 """
12 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
13 # Copyright (C) 2010-2011 The IPython Development Team
15 # Copyright (C) 2010 The IPython Development Team
14 #
16 #
15 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
@@ -20,9 +22,13 b' PUBLIC_IPS : A list of public IP addresses that point to this machine.'
20 # Imports
22 # Imports
21 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
22
24
25 import os
23 import socket
26 import socket
24
27
25 from .data import uniq_stable
28 from .data import uniq_stable
29 from .process import get_output_error_code
30 from .py3compat import bytes_to_str
31 from .warn import warn
26
32
27 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
28 # Code
34 # Code
@@ -31,7 +37,7 b' from .data import uniq_stable'
31 LOCAL_IPS = []
37 LOCAL_IPS = []
32 PUBLIC_IPS = []
38 PUBLIC_IPS = []
33
39
34 LOCALHOST = '127.0.0.1'
40 LOCALHOST = ''
35
41
36 def _only_once(f):
42 def _only_once(f):
37 """decorator to only run a function once"""
43 """decorator to only run a function once"""
@@ -51,17 +57,124 b' def _requires_ips(f):'
51 return f(*args, **kwargs)
57 return f(*args, **kwargs)
52 return ips_loaded
58 return ips_loaded
53
59
54 @_only_once
60 # subprocess-parsing ip finders
55 def _load_ips():
61 class NoIPAddresses(Exception):
56 """load the IPs that point to this machine
62 pass
63
64 def _populate_from_list(addrs):
65 """populate local and public IPs from flat list of all IPs"""
66 if not addrs:
67 raise NoIPAddresses
57
68
58 This function will only ever be called once.
69 global LOCALHOST
70 public_ips = []
71 local_ips = []
72
73 for ip in addrs:
74 local_ips.append(ip)
75 if not ip.startswith('127.'):
76 public_ips.append(ip)
77 elif not LOCALHOST:
78 LOCALHOST = ip
79
80 if not LOCALHOST:
81 LOCALHOST = '127.0.0.1'
82 local_ips.insert(0, LOCALHOST)
83
84 local_ips.extend(['0.0.0.0', ''])
85
86 LOCAL_IPS[:] = uniq_stable(local_ips)
87 PUBLIC_IPS[:] = uniq_stable(public_ips)
88
89 def _load_ips_ifconfig():
90 """load ip addresses from `ifconfig` output (posix)"""
91
92 out, err, rc = get_output_error_code('ifconfig')
93 if rc:
94 # no ifconfig, it's usually in /sbin and /sbin is not on everyone's PATH
95 out, err, rc = get_output_error_code('/sbin/ifconfig')
96 if rc:
97 raise IOError("no ifconfig: %s" % err)
98
99 lines = bytes_to_str(out).splitlines()
100 addrs = []
101 for line in lines:
102 blocks = line.lower().split()
103 if blocks[0] == 'inet':
104 addrs.append(blocks[1])
105 _populate_from_list(addrs)
106
107
108 def _load_ips_ip():
109 """load ip addresses from `ip addr` output (Linux)"""
110 out, err, rc = get_output_error_code('ip addr')
111 if rc:
112 raise IOError("no ip: %s" % err)
113
114 lines = bytes_to_str(out).splitlines()
115 addrs = []
116 for line in lines:
117 blocks = line.lower().split()
118 if blocks[0] == 'inet':
119 addrs.append(blocks[1].split('/')[0])
120 _populate_from_list(addrs)
121
122
123 def _load_ips_ipconfig():
124 """load ip addresses from `ipconfig` output (Windows)"""
125 out, err, rc = get_output_error_code('ipconfig')
126 if rc:
127 raise IOError("no ipconfig: %s" % err)
128
129 lines = bytes_to_str(out).splitlines()
130 addrs = ['127.0.0.1']
131 for line in lines:
132 line = line.lower().split()
133 if line[:2] == ['ipv4', 'address']:
134 addrs.append(line.split()[-1])
135 _populate_from_list(addrs)
136
137
138 def _load_ips_netifaces():
139 """load ip addresses with netifaces"""
140 import netifaces
141 global LOCALHOST
142 local_ips = []
143 public_ips = []
144
145 # list of iface names, 'lo0', 'eth0', etc.
146 for iface in netifaces.interfaces():
147 # list of ipv4 addrinfo dicts
148 ipv4s = netifaces.ifaddresses(iface).get(netifaces.AF_INET, [])
149 for entry in ipv4s:
150 addr = entry.get('addr')
151 if not addr:
152 continue
153 if not (iface.startswith('lo') or addr.startswith('127.')):
154 public_ips.append(addr)
155 elif not LOCALHOST:
156 LOCALHOST = addr
157 local_ips.append(addr)
158 if not LOCALHOST:
159 # we never found a loopback interface (can this ever happen?), assume common default
160 LOCALHOST = '127.0.0.1'
161 local_ips.insert(0, LOCALHOST)
162 local_ips.extend(['0.0.0.0', ''])
163 LOCAL_IPS[:] = uniq_stable(local_ips)
164 PUBLIC_IPS[:] = uniq_stable(public_ips)
165
166
167 def _load_ips_gethostbyname():
168 """load ip addresses with socket.gethostbyname_ex
169
170 This can be slow.
59 """
171 """
60 global LOCALHOST
172 global LOCALHOST
61 try:
173 try:
62 LOCAL_IPS[:] = socket.gethostbyname_ex('localhost')[2]
174 LOCAL_IPS[:] = socket.gethostbyname_ex('localhost')[2]
63 except socket.error:
175 except socket.error:
64 pass
176 # assume common default
177 LOCAL_IPS[:] = ['127.0.0.1']
65
178
66 try:
179 try:
67 hostname = socket.gethostname()
180 hostname = socket.gethostname()
@@ -74,7 +187,7 b' def _load_ips():'
74 finally:
187 finally:
75 PUBLIC_IPS[:] = uniq_stable(PUBLIC_IPS)
188 PUBLIC_IPS[:] = uniq_stable(PUBLIC_IPS)
76 LOCAL_IPS.extend(PUBLIC_IPS)
189 LOCAL_IPS.extend(PUBLIC_IPS)
77
190
78 # include all-interface aliases: 0.0.0.0 and ''
191 # include all-interface aliases: 0.0.0.0 and ''
79 LOCAL_IPS.extend(['0.0.0.0', ''])
192 LOCAL_IPS.extend(['0.0.0.0', ''])
80
193
@@ -82,6 +195,57 b' def _load_ips():'
82
195
83 LOCALHOST = LOCAL_IPS[0]
196 LOCALHOST = LOCAL_IPS[0]
84
197
198 def _load_ips_dumb():
199 """Fallback in case of unexpected failure"""
200 global LOCALHOST
201 LOCALHOST = '127.0.0.1'
202 LOCAL_IPS[:] = [LOCALHOST, '0.0.0.0', '']
203 PUBLIC_IPS[:] = []
204
205 @_only_once
206 def _load_ips():
207 """load the IPs that point to this machine
208
209 This function will only ever be called once.
210
211 It will use netifaces to do it quickly if available.
212 Then it will fallback on parsing the output of ifconfig / ip addr / ipconfig, as appropriate.
213 Finally, it will fallback on socket.gethostbyname_ex, which can be slow.
214 """
215
216 try:
217 # first priority, use netifaces
218 try:
219 return _load_ips_netifaces()
220 except ImportError:
221 pass
222
223 # second priority, parse subprocess output (how reliable is this?)
224
225 if os.name == 'nt':
226 try:
227 return _load_ips_ipconfig()
228 except (IOError, NoIPAddresses):
229 pass
230 else:
231 try:
232 return _load_ips_ifconfig()
233 except (IOError, NoIPAddresses):
234 pass
235 try:
236 return _load_ips_ip()
237 except (IOError, NoIPAddresses):
238 pass
239
240 # lowest priority, use gethostbyname
241
242 return _load_ips_gethostbyname()
243 except Exception as e:
244 # unexpected error shouldn't crash, load dumb default values instead.
245 warn("Unexpected error discovering local network interfaces: %s" % e)
246 _load_ips_dumb()
247
248
85 @_requires_ips
249 @_requires_ips
86 def local_ips():
250 def local_ips():
87 """return the IP addresses that point to this machine"""
251 """return the IP addresses that point to this machine"""
General Comments 0
You need to be logged in to leave comments. Login now