Hi Ka-Ping,
I would like to propose two enhancements for your uuid module in Python 2.5:

1) I've written functions to retrieve the MAC address that do not depend on running external programs. Please see the attached file.

2) In order to reduce the pickle footprint of UUIDs I would add a __reduce__ method to class UUID like

    def __reduce__(self):
        return (uuid, (self.int,))

together with a helper function (at module level) like

def uuid(i):
    return UUID(int=i)

Please feel free to use the supplied code.
Cheers
Michael
# 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()
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to