git.iko.soy/typeable/entropy
on main help sign in
Use POSIX directly, instead of high-level I/O

GHC's high-level openFile, etc, require the ability to identify the type of the file (directory, link, etc) in order to be able to open it. The set of type supported is incomplete, but that's not the only problem. Some systems (such as QNX) have /dev/urandom set up as a type of file that *only exists on that OS*. This is unlikely to gain proper support in GHC's high-level calls at all. Luckily, we do not need to know the type of the file in order to read it with lower-level POSIX calls. Since /dev/urandom is something we're assuming exists when on UNIX-like systems anyway, using POSIX calls in order to read it should be safe and preserve portability to all existingly-supported platforms, but will additionally allow the library to support QNX (and possibly others).

commit842ba2868450bdf0a9bc6f9e53ea73518a1a8070 authorStephen Paul Weber <singpolyma@singpolyma.net> dateSat 15 Jun 2013, 04:06 (13 years ago) parent8be62ad
2 files changed+23−16
System/Entropy.hs+21−16 entropy.cabal+2
System/Entropy.hs+21−16
@@ -16,9 +16,11 @@ module System.Entropy
1616 , closeHandle
1717 ) where
1818
19−import Control.Monad (liftM, when)
19+import Control.Monad (liftM)
2020import Data.ByteString as B
21−import System.IO (openFile, hClose, IOMode(..), Handle, withBinaryFile)
21+import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
22+import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
23+import Foreign (allocaBytes)
2224
2325#if defined(isWindows)
2426{- C example for windows rng - taken from a blog, can't recall which one but thank you!
@@ -148,7 +150,6 @@ hGetEntropy UseRdRand =
148150
149151#else
150152{- Not windows, assuming nix with a /dev/urandom -}
151−import Foreign.C.Types
152153import Foreign.Ptr
153154
154155source :: FilePath
@@ -156,7 +157,7 @@ source = "/dev/urandom"
156157
157158-- |Handle for manual resource mangement
158159data CryptHandle
159− = CH Handle
160+ = CH Fd
160161#ifdef HAVE_RDRAND
161162 | UseRdRand
162163#endif
@@ -169,18 +170,26 @@ openHandle = do
169170 if b then return UseRdRand
170171 else do
171172#endif
172− liftM CH (openFile source ReadMode)
173+ liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
173174
174175-- |Close the `CryptHandle`
175176closeHandle :: CryptHandle -> IO ()
176−closeHandle (CH h) = hClose h
177+closeHandle (CH h) = closeFd h
177178#ifdef HAVE_RDRAND
178179closeHandle UseRdRand = return ()
179180#endif
180181
182+fdReadBS :: Fd -> Int -> IO B.ByteString
183+fdReadBS fd n = do
184+ allocaBytes n $ \buf -> do
185+ rc <- fdReadBuf fd buf (fromIntegral n)
186+ case rc of
187+ 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
188+ n' -> B.packCStringLen (castPtr buf, fromIntegral n')
189+
181190-- |Read random data from a `CryptHandle`
182−hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
183−hGetEntropy (CH h) = B.hGet h
191+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
192+hGetEntropy (CH h) = fdReadBS h
184193#ifdef HAVE_RDRAND
185194hGetEntropy UseRdRand = \n -> do
186195 B.create n $ \ptr -> do
@@ -208,13 +217,9 @@ cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
208217-- entropy.
209218getEntropy :: Int -> IO B.ByteString
210219getEntropy n = do
211−#ifdef HAVE_RDRAND
212− b <- cpuHasRdRand
213− if b then hGetEntropy UseRdRand n
214− else do
215−#endif
216−{- arch_x86 -}
217− withBinaryFile source ReadMode (`B.hGet` n)
220+ h <- openHandle
221+ e <- hGetEntropy h n
222+ closeHandle h
223+ return e
218224#endif
219225{- OS Test -}
220−
entropy.cabal+2
@@ -34,6 +34,8 @@ Library
3434 if os(windows)
3535 cpp-options: -DisWindows
3636 extra-libraries: advapi32
37+ else
38+ Build-Depends: unix
3739
3840source-repository head
3941 type: git