Package node_manager_fkie :: Module name_resolution
[frames] | no frames]

Source Code for Module node_manager_fkie.name_resolution

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2012, Fraunhofer FKIE/US, Alexander Tiderko 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Fraunhofer nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32   
 33  from threading import Thread, RLock 
 34  from urlparse import urlparse 
 35  import socket 
 36   
 37  import rospy 
 38  from master_discovery_fkie.common import get_hostname 
 39   
 40  RESOLVE_CACHE = {}  # hostname : address 
41 42 43 -class MasterEntry(object):
44
45 - def __init__(self, masteruri=None, mastername=None, address=None):
46 self.masteruri = masteruri 47 self._masternames = [] 48 self.add_mastername(mastername) 49 self.mutex = RLock() 50 # addresses: hostname (at first place if available), IPv4 or IPv6 51 self._addresses = [] 52 self.add_address(address)
53
54 - def __repr__(self):
55 return ''.join([str(self.masteruri), ':\n', 56 ' masternames: ', str(self._masternames), '\n', 57 ' addresses: ', str(self._addresses), '\n'])
58
59 - def entry(self):
60 return (self.masteruri, list(self._masternames), list(self._addresses))
61
62 - def has_mastername(self, mastername):
63 return mastername in self._masternames
64
65 - def has_address(self, address):
66 with self.mutex: 67 return address in self._addresses
68
69 - def add_mastername(self, mastername):
70 if mastername and mastername not in self._masternames: 71 self._masternames.append(mastername)
72
73 - def add_address(self, address):
74 if address and not self.has_address(address): 75 if self.is_legal_ip(address): 76 # it is an IP, try to get the hostname 77 with self.mutex: 78 self._addresses.append(address) 79 # resolve the name in a thread 80 thread = Thread(target=self._get_hostname, args=((address,))) 81 thread.daemon = True 82 thread.start() 83 else: 84 # it is a hostname: add at the fist place and try to get an IP for this host 85 with self.mutex: 86 self._addresses.insert(0, address) 87 # resolve the name in a thread 88 thread = Thread(target=self._get_address, args=((address,))) 89 thread.daemon = True 90 thread.start()
91 92 @classmethod 109
110 - def _get_address(self, hostname):
111 try: 112 (_, _, ipaddrlist) = socket.gethostbyaddr(hostname) 113 with self.mutex: 114 if ipaddrlist: 115 RESOLVE_CACHE[hostname] = ipaddrlist 116 for addr in ipaddrlist: 117 if not self.has_address(addr): 118 self._addresses.append(addr) 119 except socket.gaierror: 120 # no suitable address found 121 pass
122
123 - def _get_hostname(self, address):
124 try: 125 (hostname, _, _) = socket.gethostbyaddr(address) 126 with self.mutex: 127 name_splitted = hostname.split('.') 128 RESOLVE_CACHE[address] = [name_splitted[0], hostname] 129 if not self.has_address(hostname): 130 self._addresses.insert(0, hostname) 131 if not self.has_address(name_splitted[0]): 132 self._addresses.insert(0, name_splitted[0]) 133 except socket.gaierror: 134 # no suitable address found 135 pass
136
137 - def get_mastername(self):
138 try: 139 return self._masternames[0] 140 except: 141 return None
142
143 - def get_masternames(self):
144 return list(self._masternames)
145
146 - def get_address(self):
147 with self.mutex: 148 try: 149 return self._addresses[0] 150 except: 151 return None
152
153 - def addresses(self):
154 return list(self._addresses)
155
156 - def remove_mastername(self, mastername):
157 try: 158 self._masternames.remove(mastername) 159 except: 160 pass
161
162 - def remove_address(self, address):
163 try: 164 self._addresses.remove(address) 165 except: 166 pass
167
168 169 -class NameResolution(object):
170 ''' 171 This class stores the association between master URI, master name and 172 host name or IP. Both the setter and the getter methods are thread safe. 173 ''' 174
175 - def __init__(self):
176 self.mutex = RLock() 177 self._masters = [] # sets with masters 178 self._hosts = [] # sets with hosts 179 self._address = [] # avoid the mixing of ip and name as address
180
181 - def remove_master_entry(self, masteruri):
182 with self.mutex: 183 for m in self._masters: 184 if masteruri and m.masteruri == masteruri: 185 self._masters.remove(m) 186 return
187
188 - def remove_info(self, mastername, address):
189 with self.mutex: 190 for m in self._masters: 191 if m.has_mastername(mastername) and m.has_address(address): 192 m.remove_mastername(mastername) 193 m.remove_address(address) 194 return
195
196 - def add_master_entry(self, masteruri, mastername, address):
197 with self.mutex: 198 mastername = self._validate_mastername(mastername, masteruri) 199 for m in self._masters: 200 if m.masteruri and m.masteruri == masteruri: 201 m.add_mastername(mastername) 202 m.add_address(address) 203 return 204 elif m.masteruri is None and m.has_mastername(mastername): 205 m.masteruri = masteruri 206 m.add_mastername(mastername) 207 m.add_address(address) 208 return 209 self._masters.append(MasterEntry(masteruri, mastername, address))
210
211 - def add_info(self, mastername, address):
212 with self.mutex: 213 for m in self._masters: 214 if m.has_mastername(mastername): 215 m.add_mastername(mastername) 216 m.add_address(address) 217 return 218 if mastername is not None: 219 self._masters.append(MasterEntry(None, mastername, address))
220
221 - def _validate_mastername(self, mastername, masteruri):
222 ''' 223 Not thead safe 224 ''' 225 mm = self.masteruri(mastername) 226 if mm and mm != masteruri: 227 nr = 2 228 new_name = '%s_%d' % (mastername, nr) 229 while mm and mm != masteruri: 230 new_name = '%s_%d' % (mastername, nr) 231 nr = nr + 1 232 rospy.logwarn("master name '%s' is already assigned to '%s', rename to '%s'"(mastername, mm, new_name)) 233 return new_name 234 return mastername
235
236 - def has_master(self, masteruri):
237 with self.mutex: 238 for m in self._masters: 239 if m.masteruri == masteruri: 240 return True 241 return False
242
243 - def mastername(self, masteruri, address=None):
244 with self.mutex: 245 for m in self._masters: 246 if m.masteruri == masteruri: 247 if address is not None: 248 if m.has_address(address): 249 return m.get_mastername() 250 else: 251 return m.get_mastername() 252 return None
253
254 - def masternames(self, masteruri):
255 with self.mutex: 256 for m in self._masters: 257 if m.masteruri == masteruri: 258 return m.get_masternames() 259 return list()
260
261 - def masternamebyaddr(self, address):
262 with self.mutex: 263 for m in self._masters: 264 if m.has_address(address): 265 return m.get_mastername() 266 return None
267
268 - def masteruri(self, mastername):
269 with self.mutex: 270 for m in self._masters: 271 if m.has_mastername(mastername): 272 return m.masteruri 273 return None
274
275 - def masterurisbyaddr(self, address):
276 with self.mutex: 277 result = [] 278 for m in self._masters: 279 if m.has_address(address) and m.masteruri and m.masteruri not in result: 280 result.append(m.masteruri) 281 return result
282
283 - def address(self, masteruri):
284 with self.mutex: 285 for m in self._masters: 286 if m.masteruri == masteruri or m.has_mastername(masteruri): 287 return m.get_address() 288 return None
289
290 - def addresses(self, masteruri):
291 with self.mutex: 292 for m in self._masters: 293 if m.masteruri == masteruri or m.has_mastername(masteruri): 294 return m.addresses() 295 return []
296
297 - def hostname(self, address, resolve=False):
298 with self.mutex: 299 for m in self._masters: 300 if m.has_address(address) or m.has_mastername(address): 301 result = m.get_address() 302 if result and not MasterEntry.is_legal_ip(result): 303 return result 304 else: 305 break 306 try: 307 if MasterEntry.is_legal_ip(address): 308 (hostname, _, _) = socket.gethostbyaddr(address) 309 return hostname 310 except: 311 import traceback 312 print traceback.format_exc() 313 return address
314 315 @classmethod
316 - def masteruri2name(cls, masteruri):
317 result = masteruri 318 try: 319 url = urlparse(masteruri) 320 if url.port == 11311: 321 result = '%s' % url.hostname 322 else: 323 result = '%s_%d' % (url.hostname, url.port) 324 except: 325 pass 326 return cls.normalize_name(result)
327 328 @classmethod
329 - def normalize_name(cls, name):
330 result = name.replace('-', '_').replace('.', '_') 331 return result
332 333 @classmethod 336
337 - def resolve_cached(self, hostname):
338 try: 339 return RESOLVE_CACHE[hostname] 340 except: 341 pass 342 return [hostname]
343 344 @classmethod
345 - def get_ros_hostname(cls, url):
346 ''' 347 Returns the host name used in a url, if it is a name. If it is an IP an 348 empty string will be returned. 349 350 @return: host or '' if url is an IP or invalid 351 @rtype: C{str} 352 ''' 353 hostname = get_hostname(url) 354 if hostname is not None: 355 if hostname != 'localhost': 356 if '.' not in hostname and ':' not in hostname: 357 local_hostname = 'localhost' 358 try: 359 # ROS resolves the 'localhost' to local hostname 360 local_hostname = socket.gethostname() 361 except: 362 pass 363 if hostname != local_hostname: 364 return hostname 365 return ''
366