How to create an UUID (Version 1)

new topic     » topic index » view thread      » older message » newer message

Here is my code to generate an universally unique identifier (UUID) version 1 that conforms to RFC4122. It needs OE4.1 on Linux, libpcap0.8 (to detect main network interface).

include std/math.e 
include std/datetime.e 
include std/os.e 
include std/dll.e 
include std/machine.e 
include std/socket.e 
 
-- UUID 
-- 
-- A UUID is 128 bit long, and consists of a 60-bit time value, a 16-bit sequence number and a 48-bit node identifier. 
-- 
-- <time>-<sequence>-<mac address> 
--   60       16           48 
-- <time> number of 100-nanosecond intervals since midnight 15 October 1582 Coordinated Universal Time (UTC), the date on which the Gregorian calendar was first adopted. 
-- 
-- In its canonical textual representation, the sixteen octets of a UUID are represented as 32 hexadecimal (base 16) digits, displayed in five groups separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters (32 alphanumeric characters and four hyphens). For example: 
-- 
--     123e4567-e89b-12d3-a456-426655440000 
--     xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx 
-- 
-- The four bits of digit M indicate the UUID version, and the one to three most significant bits of digit N indicate the UUID variant. In the example, M is 1 and N is a (10xx), meaning that the UUID is a variant 1, version 1 UUID; that is, a time-based DCE/RFC 4122 UUID. 
-- 
-- The canonical 8-4-4-4-12 format string is based on the "record layout" for the 16 bytes of the UUID:[2] 
-- 
-- UUID record layout 
-- 
-- Name                             Length      Length     Contents 
--                                  (bytes)  (hex digits) 
-- time_low                            4          8        integer giving the low 32 bits of the time 
-- time_mid                            2          4        integer giving the middle 16 bits of the time 
-- time_hi_and_version                 2          4        4-bit "version" in the most significant bits, followed by the high 12 bits of the time 
-- clock_seq_hi_and_res clock_seq_low  2          4        1-3 bit "variant" in the most significant bits, followed by the 13-15 bit clock sequence 
-- node                                6         12        the 48-bit node id 
 
------------------------------------------------------------------------------ 
 
public constant 
  NORMAL = 1, REVERSE = 2 
 
constant 
  PCAP_ERRBUF_SIZE = 256 
 
constant 
  libc = open_dll("") 
 
atom pcap = -1 
 
ifdef UNIX then 
  sequence un = uname() 
  sequence arch = un[5] 
  -- following lines work for Ubuntu derivatives 
  -- with other Linux distributions please update corresponding lines 
  if equal(arch, "i686") then 
    pcap = open_dll("/usr/lib/i386-linux-gnu/libpcap.so") 
  elsif equal(arch, "x86_64") then 
    pcap = open_dll("/usr/lib/x86_64-linux-gnu/libpcap.so") 
  elsif equal(arch, "armv7l") then 
    pcap = open_dll("/usr/lib/arm-linux-gnueabihf/libpcap.so.0.8") 
  end if 
end ifdef 
if pcap = -1 then 
  puts(1,"Could not open libpcap library!\n") 
  abort(0) 
end if 
 
constant 
  xpcap_lookupdev = define_c_func(pcap, "pcap_lookupdev", {C_POINTER}, C_POINTER), 
  ioctl_         = define_c_func(libc, "ioctl",{C_INT,C_INT,C_INT},C_INT), 
  socket_        = define_c_func(libc, "socket",{C_INT,C_INT,C_INT},C_INT) 
 
------------------------------------------------------------------------------ 
 
function hex_string(sequence s) 
  sequence result = "" 
  for i = 1 to length(s) do 
    result &= sprintf("%02x", s[i]) 
  end for 
  return result 
end function 
 
------------------------------------------------------------------------------- 
 
function uint_to_bytes(atom n, integer digits, integer direction=REVERSE) 
  sequence s = repeat(0, digits) 
  if direction = NORMAL then 
    for i = digits to 1 by -1 do 
      s[i] = remainder(n, #100) 
      n = floor(n / #100) 
    end for 
  elsif direction = REVERSE then 
    for i = 1 to digits do 
      s[i] = remainder(n, #100) 
      n = floor(n / #100) 
    end for 
  end if 
  return s 
end function 
 
------------------------------------------------------------------------------ 
 
function get_iface_hw_addr(sequence iface_name) 
  sequence hw_addr 
  atom ifreq, sockid, status 
 
  hw_addr = "" 
  ifreq = allocate(200) 
  sockid = c_func(socket_,{AF_INET,SOCK_DGRAM,0}) 
  if sockid < 0 then 
    free(ifreq) 
    return {} 
  end if 
  poke(ifreq,iface_name&0) 
  status = c_func(ioctl_,{sockid,#8927,ifreq}) -- HW Address 
  if status >= 0 then 
    hw_addr = "" 
    for ctr = 18 to 23 do 
      hw_addr = hw_addr & sprintf("%02x",peek(ifreq+ctr)) 
    end for 
    hw_addr = hw_addr[1..length(hw_addr)] 
  end if 
  return hw_addr 
end function 
 
------------------------------------------------------------------------------ 
 
function pcap_lookupdev() 
  atom error_buffer = allocate(PCAP_ERRBUF_SIZE) 
  sequence ret 
  atom device = c_func(xpcap_lookupdev, {error_buffer}) 
  if device = NULL then 
    ret = {0, peek_string(error_buffer)} 
  end if 
  free(error_buffer) 
  ret = {1, peek_string(device)} 
  return ret 
end function 
 
------------------------------------------------------------------------------ 
 
function gregorian_time() 
  sequence dt = now_gmt() 
  sequence from = new(1582,10,15, 0, 0, 0) 
  atom nb = trunc(diff(from, dt)*10_000_000) 
  return nb 
end function 
 
------------------------------------------------------------------------------ 
 
function create_uuid() 
  sequence hw_addr, iface_name 
  integer ok 
 
  sequence uuid = "" 
  sequence s = uint_to_bytes(gregorian_time(), 8, NORMAL) 
  sequence gt = hex_string(s) 
  sequence time_low = tail(gt, 8) 
  gt = gt[1..$-8] 
  sequence time_mid = tail(gt, 4) 
  gt = gt[1..$-4] 
  sequence time_hi = tail(gt, 3) 
 
  sequence dt = now() 
  sequence midnight = dt[1..3] & {0,0,0} 
  s = uint_to_bytes(remainder(diff(midnight, dt),3600), 2, NORMAL) 
  sequence clock_seq = hex_string(s) 
  integer n = clock_seq[1] - #30 
  clock_seq[1] = #30 + (8 + and_bits(n, #3)) 
 
  {ok, iface_name} = pcap_lookupdev() 
  if ok then 
    hw_addr = get_iface_hw_addr(iface_name) 
  else 
    puts(2, "No interface found!\n") 
  end if 
 
  uuid = time_low & "-" & time_mid & "-1" &  time_hi & 
         "-" & clock_seq & "-" & hw_addr 
  return uuid 
end function 
 
------------------------------------------------------------------------------ 
 
sequence s = create_uuid() 
puts(1, s & "\n") 

libpcap cant be forgotten if you specify the default interface as a parameter to create_uuid().

Regards

Jean-Marc

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu