Permalink
Browse files

Merge branch 'rubymacaddr' of https://github.com/mikezter/uuid into m…

…ikezter-rubymacaddr
  • Loading branch information...
2 parents 80f4ea9 + 2fc1d15 commit 8f56f44e8d0151c44fafca9dda4a2eb2f8e1e492 @assaf committed Apr 11, 2011
Showing with 70 additions and 5 deletions.
  1. +52 −2 lib/uuid.rb
  2. +18 −3 test/test-uuid.rb
View
@@ -11,6 +11,7 @@
require 'tmpdir'
require 'socket'
require 'macaddr'
+require 'digest/sha1'
##
@@ -195,6 +196,55 @@ def self.validate(uuid)
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
@drift = 0
@@ -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
View
@@ -4,6 +4,7 @@
# License:: MIT and/or Creative Commons Attribution-ShareAlike
require 'test/unit'
+require 'rubygems'
require 'uuid'
class TestUUID < Test::Unit::TestCase
@@ -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,
@@ -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
@@ -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.