Uniform.hs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. {-# LANGUAGE ExistentialQuantification #-}
  2. -- {-# LANGUAGE OverloadedStrings #-}
  3. -- {-# LANGUAGE ForeignFunctionInterface #-}
  4. -- {-# LANGUAGE InterruptibleFFI #-}
  5. -- {-# LANGUAGE EmptyDataDecls #-}
  6. -- |
  7. -- Uniform-IO provides a typeclass for uniform access of different types of targets,
  8. -- and implementations for abstracting standard streams, files and network connections.
  9. -- This module also provides TLS wraping over other IO targets.
  10. module System.IO.Uniform (
  11. UniformIO(..),
  12. TlsSettings(..),
  13. SomeIO(..), TlsIO,
  14. mapOverInput
  15. ) where
  16. import System.IO.Uniform.External
  17. import Foreign
  18. --import Foreign.C.Types
  19. --import Foreign.C.String
  20. import Foreign.C.Error
  21. --import qualified Data.IP as IP
  22. import Data.ByteString (ByteString)
  23. import qualified Data.ByteString as BS
  24. --import qualified Data.ByteString.Lazy as LBS
  25. --import qualified Data.ByteString.Builder as BSBuild
  26. --import qualified Data.List as L
  27. import Control.Exception
  28. import Control.Applicative ((<$>))
  29. --import Data.Monoid (mappend)
  30. --import qualified Network.Socket as Soc
  31. import System.IO.Error
  32. --import Control.Concurrent.MVar
  33. import Data.Default.Class
  34. import System.Posix.Types (Fd(..))
  35. -- |
  36. -- Typeclass for uniform IO targets.
  37. class UniformIO a where
  38. -- | uRead fd n
  39. --
  40. -- Reads a block of at most n bytes of data from the IO target.
  41. -- Reading will block if there's no data available, but will return immediately
  42. -- if any amount of data is availble.
  43. --
  44. -- Must thow System.IO.Error.EOFError if reading beihond EOF.
  45. uRead :: a -> Int -> IO ByteString
  46. -- | uPut fd text
  47. --
  48. -- Writes all the bytes of text into the IO target. Takes care of retrying if needed.
  49. uPut :: a -> ByteString -> IO ()
  50. -- | fClose fd
  51. --
  52. -- Closes the IO target, releasing any allocated resource. Resources may leak if not called
  53. -- for every oppened fd.
  54. uClose :: a -> IO ()
  55. -- | startTLS fd
  56. --
  57. -- Starts a TLS connection over the IO target.
  58. startTls :: TlsSettings -> a -> IO TlsIO
  59. -- | isSecure fd
  60. --
  61. -- Indicates whether the data written or read from fd is secure at transport.
  62. isSecure :: a -> Bool
  63. -- | A type that wraps any type in the UniformIO class.
  64. data SomeIO = forall a. (UniformIO a) => SomeIO a
  65. instance UniformIO SomeIO where
  66. uRead (SomeIO s) n = uRead s n
  67. uPut (SomeIO s) t = uPut s t
  68. uClose (SomeIO s) = uClose s
  69. startTls set (SomeIO s) = startTls set s
  70. isSecure (SomeIO s) = isSecure s
  71. -- | Settings for starttls functions.
  72. data TlsSettings = TlsSettings {tlsPrivateKeyFile :: String, tlsCertificateChainFile :: String, tlsDHParametersFile :: String} deriving (Read, Show)
  73. instance Default TlsSettings where
  74. def = TlsSettings "" "" ""
  75. -- | UniformIO wrapper that applies TLS to communication on IO target.
  76. -- This type is constructed by calling startTls on other targets.
  77. instance UniformIO TlsIO where
  78. uRead s n = do
  79. allocaArray n (
  80. \b -> do
  81. count <- c_recvTls (tls s) b $ fromIntegral n
  82. if count < 0
  83. then throwErrno "could not read"
  84. else BS.packCStringLen (b, fromIntegral count)
  85. )
  86. uPut s t = do
  87. BS.useAsCStringLen t (
  88. \(str, n) -> do
  89. count <- c_sendTls (tls s) str $ fromIntegral n
  90. if count < 0
  91. then throwErrno "could not write"
  92. else return ()
  93. )
  94. uClose s = do
  95. d <- c_closeTls (tls s)
  96. f <- Fd <$> c_prepareToClose d
  97. closeFd f
  98. startTls _ s = return s
  99. isSecure _ = True
  100. -- | mapOverInput io block_size f initial
  101. -- Reads io untill the end of file, evaluating a(i) <- f a(i-1) read_data
  102. -- where a(0) = initial and the last value after io reaches EOF is returned.
  103. --
  104. -- Notice that the length of read_data might not be equal block_size.
  105. mapOverInput :: forall a io. UniformIO io => io -> Int -> (a -> ByteString -> IO a) -> a -> IO a
  106. mapOverInput io block f initial = do
  107. a <- tryIOError $ uRead io block
  108. case a of
  109. Left e -> if isEOFError e then return initial else throw e -- EOF
  110. Right dt -> do
  111. i <- f initial dt
  112. mapOverInput io block f i