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
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com