# helper functions for determining host id def _getMACAddrPosix(api=None): import array, fcntl, socket if api == 'cygwin': # doesn't work currently due to a bug in cygwin python: # cygwins SIOCGIF* are unsigned int greater than sys.maxint # but fcntl.ioctl tries to convert them to an int SIOCGIFCONF = 0x80087364L SIOCGIFNAME = 0 # not defined on cygwin SIOCGIFHWADDR = 0x80207369L else: # default SIOCGIF* (taken from Linux) SIOCGIFCONF = 0x8912 SIOCGIFNAME = 0x8910 SIOCGIFHWADDR = 0x8927 # function to get MAC address def getHwAddr(ifName): ifReq = _struct.pack('16s16s', ifName, '') ifReq = fcntl.ioctl(sock, SIOCGIFHWADDR, ifReq) ifn, ift, ifah, ifal = _struct.unpack('>16sHHL8x', ifReq) return (long(ifah)<<32) + ifal sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) try: # first try SIOCGIFCONF try: maxIfs = 32 lenIfReq = 32 # length of struct ifreq lenBuf = lenIfReq * maxIfs buf = array.array('c', '\0' * lenBuf) ifConf = _struct.pack('iP', lenBuf, buf.buffer_info()[0]) ifConf = fcntl.ioctl(sock, SIOCGIFCONF, ifConf) lenBuf, ptr = _struct.unpack('iP', ifConf) nIfs = lenBuf // lenIfReq for i in range(nIfs): offset = i * lenIfReq ifReq = buf.tostring()[offset : offset + lenIfReq] ifName, fill = _struct.unpack("16s16s", ifReq) if ifName != 'lo': macAddr = getHwAddr(ifName) if macAddr != 0: return macAddr except: pass # next try SIOCGIFNAME ifIdx = 1 try: assert SIOCGIFNAME != 0 # SIOCGIFNAME defined? while True: ifReq = _struct.pack('16si12x', '', ifIdx) ifReq = fcntl.ioctl(sock, SIOCGIFNAME, ifReq) ifName, fill = _struct.unpack('16s16s', ifReq) if ifName != 'lo': macAddr = getHwAddr(ifName) if macAddr != 0: return macAddr ifIdx += 1 except: pass # next try to get if list via procfs try: devs = open('/proc/net/dev', 'r') try: for l in devs: i = l.find(':') if 0 < i <= 16: ifName = l[:i].strip() if ifName != 'lo': macAddr = getHwAddr(ifName) if macAddr != 0: return macAddr finally: devs.close() except: pass finally: sock.close() return None def _getMACAddrLinux(): try: sysnet = '/sys/class/net' for ifn in _os.listdir(sysnet): fAddr = open(_os.path.join(sysnet, ifn, 'address')) sAddr = fAddr.readline().replace(':','').strip() if len(sAddr) == 12: macAddr = long("0x%s"%sAddr, 16) if macAddr != 0: return macAddr except: pass return _getMACAddrPosix() def _getMACAddrWin(): try: from ctypes import Structure, windll, sizeof from ctypes import POINTER, byref, SetPointerType from ctypes import c_ulonglong, c_ulong, c_uint, c_ubyte, c_char MAX_ADAPTER_DESCRIPTION_LENGTH = 128 MAX_ADAPTER_NAME_LENGTH = 256 MAX_ADAPTER_ADDRESS_LENGTH = 8 class IP_ADDR_STRING(Structure): pass LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING) IP_ADDR_STRING._fields_ = [ ("next", LP_IP_ADDR_STRING), ("ipAddress", c_char * 16), ("ipMask", c_char * 16), ("context", c_ulong)] class IP_ADAPTER_INFO (Structure): pass LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO) IP_ADAPTER_INFO._fields_ = [ ("next", LP_IP_ADAPTER_INFO), ("comboIndex", c_ulong), ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)), ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)), ("addressLength", c_uint), ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH), ("index", c_ulong), ("type", c_uint), ("dhcpEnabled", c_uint), ("currentIpAddress", LP_IP_ADDR_STRING), ("ipAddressList", IP_ADDR_STRING), ("gatewayList", IP_ADDR_STRING), ("dhcpServer", IP_ADDR_STRING), ("haveWins", c_uint), ("primaryWinsServer", IP_ADDR_STRING), ("secondaryWinsServer", IP_ADDR_STRING), ("leaseObtained", c_ulong), ("leaseExpires", c_ulong)] GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo GetAdaptersInfo.restype = c_ulong GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)] adapterList = (IP_ADAPTER_INFO * 10)() buflen = c_ulong(sizeof(adapterList)) rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen)) if rc == 0: for a in adapterList: l = a.addressLength if l == 6: return reduce(lambda x, y: (long(x)<<8) + y, a.address[0:l]) if a.index == 0: break return None except: return None def _getHostIdFromHash(): import socket, platform, md5 host = socket.getfqdn() h=md5.md5(host+platform.system()+platform.release()+platform.version()) for k,v in _os.environ.items(): h.update(k) h.update(v) return long(h.hexdigest(),16)%2**47 + 2**47 # bit 47 = 1 -> multicast # so there's no conflict # with addresses obtained # from network adapters def _getHostId(): import os, sys api = sys.platform # First, try to retrieve the MAC address of a network adapter macAddr = None if api == 'linux2': macAddr = _getMACAddrLinux() elif api == 'win32': macAddr = _getMACAddrWin() elif _os.name == 'posix': macAddr = _getMACAddrPosix(api) if macAddr: return macAddr # Couldn't get a MAC address, so create hash return _getHostIdFromHash() _hostId = _getHostId()