Skip to content

Commit

Permalink
Merge branch 'rubymacaddr' of https://github.com/mikezter/uuid into m…
Browse files Browse the repository at this point in the history
…ikezter-rubymacaddr
  • Loading branch information
assaf committed Apr 11, 2011
2 parents 80f4ea9 + 2fc1d15 commit 8f56f44
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 5 deletions.
54 changes: 52 additions & 2 deletions lib/uuid.rb
Expand Up @@ -11,6 +11,7 @@
require 'tmpdir'
require 'socket'
require 'macaddr'
require 'digest/sha1'


##
Expand Down Expand Up @@ -194,6 +195,55 @@ def self.validate(uuid)
uuid =~ /\A(urn:uuid:)?[\da-f]{8}-([\da-f]{4}-){3}[\da-f]{12}\z/i
end

##
# Generate a pseudo MAC address because we have no pure-ruby way
# to know the MAC address of the NIC this system uses. Note
# that cheating with pseudo arresses here is completely legal:
# see Section 4.5 of RFC4122 for details.
#
# This implementation is shamelessly stolen from
# https://github.com/spectra/ruby-uuid/blob/master/uuid.rb
# Thanks spectra.
#
def pseudo_mac_address
sha1 = ::Digest::SHA1.new
256.times do
r = [rand(0x100000000)].pack "N"
sha1.update r
end
str = sha1.digest
r = rand 14 # 20-6
node = str[r, 6] || str
if RUBY_VERSION >= "1.9.0"
nnode = node.bytes.to_a
nnode[0] |= 0x01
node = ''
nnode.each { |s| node << s.chr }
else
node[0] |= 0x01 # multicast bit
end
node.bytes.collect{|b|b.to_s(16)}.join.hex & 0x7FFFFFFFFFFF
end

##
# Uses system calls to get a mac address
#
def iee_mac_address
begin
Mac.addr.gsub(/:|-/, '').hex & 0x7FFFFFFFFFFF
rescue
0
end
end

##
# return iee_mac_address if available, pseudo_mac_address otherwise
#
def mac_address
return iee_mac_address unless iee_mac_address == 0
return pseudo_mac_address
end

##
# Create a new UUID generator. You really only need to do this once.
def initialize
Expand All @@ -205,8 +255,8 @@ def initialize
if state_file && File.size?(state_file) then
next_sequence
else
@mac = Mac.addr.gsub(/:|-/, '').hex & 0x7FFFFFFFFFFF
fail "Cannot determine MAC address from any available interface, tried with #{Mac.addr}" if @mac == 0
@mac = mac_address
fail "Cannot determine MAC address from any available interface, tried with #{mac_address}" if @mac == 0
@sequence = rand 0x10000

if state_file
Expand Down
21 changes: 18 additions & 3 deletions test/test-uuid.rb
Expand Up @@ -4,6 +4,7 @@
# License:: MIT and/or Creative Commons Attribution-ShareAlike

require 'test/unit'
require 'rubygems'
require 'uuid'

class TestUUID < Test::Unit::TestCase
Expand Down Expand Up @@ -31,8 +32,7 @@ def test_with_no_state_file
assert !UUID.state_file
end

def test_instance_generate
uuid = UUID.new
def validate_uuid_generator(uuid)
assert_match(/\A[\da-f]{32}\z/i, uuid.generate(:compact))

assert_match(/\A[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}\z/i,
Expand All @@ -44,8 +44,13 @@ def test_instance_generate
e = assert_raise ArgumentError do
uuid.generate :unknown
end

assert_equal 'invalid UUID format :unknown', e.message

end

def test_instance_generate
uuid = UUID.new
validate_uuid_generator(uuid)
end

def test_class_generate
Expand Down Expand Up @@ -108,5 +113,15 @@ class << bar = UUID.new
assert_equal foo.sequence + 1, bar.sequence
end

def test_pseudo_random_mac_address
uuid_gen = UUID.new
def Mac.addr; '00:00:00:00:00:00'; end
assert uuid_gen.iee_mac_address == 0
[:compact, :default, :urn].each do |format|
assert UUID.validate(uuid_gen.generate(format)), format.to_s
end
validate_uuid_generator(uuid_gen)
end

end

0 comments on commit 8f56f44

Please sign in to comment.