@@ -5,7 +5,7 @@
55-- Module : Data.UUID.V1
66-- Copyright : (c) 2008 Jason Dusek
77-- (c) 2009 Mark Lentczner
8−-- (c) 2009-2010 Antoine Latter
8+-- (c) 2009-2010,2012 Antoine Latter
99--
1010-- License : BSD-style
1111--
@@ -23,9 +23,12 @@ import Data.Time
2323import Data.Bits
2424import Data.Word
2525
26+import Control.Applicative ((<$>),(<*>))
2627import Control.Concurrent.MVar
2728import System.IO.Unsafe
2829
30+import qualified System.Random as R
31+
2932import qualified System.Info.MAC as SysMAC
3033import Data.MAC
3134
@@ -42,9 +45,8 @@ import Data.UUID.Internal
4245nextUUID :: IO (Maybe UUID)
4346nextUUID = do
4447 res <- stepTime
45− mac <- SysMAC.mac
46− case (res, mac) of
47− (Just (c, t), Just m) -> return $ Just $ makeUUID t c m
48+ case res of
49+ Just (mac, c, t) -> return $ Just $ makeUUID t c mac
4850 _ -> return Nothing
4951
5052
@@ -64,20 +66,20 @@ type instance ByteSink MACSource g = Takes3Bytes (Takes3Bytes g)
6466-- |Approximates the clock algorithm in RFC 4122, section 4.2
6567-- Isn't system wide or thread safe, nor does it properly randomize
6668-- the clock value on initialization.
67−stepTime :: IO (Maybe (Word16, Word64))
69+stepTime :: IO (Maybe (MAC, Word16, Word64))
6870stepTime = do
6971 h1 <- fmap hundredsOfNanosSinceGregorianReform getCurrentTime
70− modifyMVar state $ \s@(State c0 h0) ->
72+ modifyMVar state $ \s@(State mac c0 h0) ->
7173 if h1 > h0
7274 then
73− return (State c0 h1, Just (c0, h1))
75+ return (State mac c0 h1, Just (mac, c0, h1))
7476 else
7577 let
7678 c1 = succ c0
7779 in if c1 <= 0x3fff -- when clock is initially randomized,
7880 -- then this test will need to change
7981 then
80− return (State c1 h1, Just (c1, h1))
82+ return (State mac c1 h1, Just (mac, c1, h1))
8183 else
8284 return (s, Nothing)
8385
@@ -86,10 +88,33 @@ stepTime = do
8688state :: MVar State
8789state = unsafePerformIO $ do
8890 h0 <- fmap hundredsOfNanosSinceGregorianReform getCurrentTime
89− newMVar $ State 0 h0 -- the 0 should be a random number
90−
91+ mac <- getMac
92+ newMVar $ State mac 0 h0 -- the 0 should be a random number
93+
94+-- SysMAC.mac can fail on some machines.
95+-- In those cases we fake it with a random
96+-- 6 bytes seed.
97+getMac :: IO MAC
98+getMac =
99+ SysMAC.mac >>= \macM ->
100+ case macM of
101+ Just m -> return m
102+ Nothing -> randomMac
103+
104+randomMac :: IO MAC
105+randomMac =
106+ -- I'm too lazy to thread through
107+ -- the random state ...
108+ MAC
109+ <$> R.randomIO
110+ <*> R.randomIO
111+ <*> R.randomIO
112+ <*> R.randomIO
113+ <*> R.randomIO
114+ <*> R.randomIO
91115
92116data State = State
117+ {-# UNPACK #-} !MAC
93118 {-# UNPACK #-} !Word16
94119 {-# UNPACK #-} !Word64
95120 deriving (Show)