2014-01-10 07:01:34 +00:00
|
|
|
-- |
|
|
|
|
-- Module : Network.TLS.Backend
|
|
|
|
-- License : BSD-style
|
|
|
|
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
|
|
|
|
-- Stability : experimental
|
|
|
|
-- Portability : unknown
|
|
|
|
--
|
|
|
|
-- Backend represent a unified way to do IO on differents
|
|
|
|
-- types without burdening our calling API with multiples
|
|
|
|
-- way to initialize a new context.
|
|
|
|
--
|
|
|
|
-- Typically any backend much implement:
|
|
|
|
-- * a way to read data
|
|
|
|
-- * a way to write data
|
|
|
|
-- * a way to close the stream
|
|
|
|
-- * a way to flush the stream
|
|
|
|
--
|
|
|
|
module Network.TLS.Backend
|
|
|
|
( HasBackend(..)
|
|
|
|
, Backend(..)
|
|
|
|
) where
|
|
|
|
|
|
|
|
import Control.Monad
|
|
|
|
import Network.Socket (Socket, sClose)
|
|
|
|
import qualified Network.Socket.ByteString as Socket
|
|
|
|
import Data.ByteString (ByteString)
|
|
|
|
import qualified Data.ByteString as B
|
2014-01-17 06:55:33 +00:00
|
|
|
import System.IO (Handle, hSetBuffering, BufferMode(..), hFlush, hClose)
|
2014-01-10 07:01:34 +00:00
|
|
|
|
|
|
|
-- | Connection IO backend
|
|
|
|
data Backend = Backend
|
|
|
|
{ backendFlush :: IO () -- ^ Flush the connection sending buffer, if any.
|
|
|
|
, backendClose :: IO () -- ^ Close the connection.
|
|
|
|
, backendSend :: ByteString -> IO () -- ^ Send a bytestring through the connection.
|
|
|
|
, backendRecv :: Int -> IO ByteString -- ^ Receive specified number of bytes from the connection.
|
|
|
|
}
|
|
|
|
|
|
|
|
class HasBackend a where
|
2014-01-17 06:55:33 +00:00
|
|
|
initializeBackend :: a -> IO ()
|
2014-01-10 07:01:34 +00:00
|
|
|
getBackend :: a -> Backend
|
|
|
|
|
|
|
|
instance HasBackend Backend where
|
2014-01-17 06:55:33 +00:00
|
|
|
initializeBackend _ = return ()
|
2014-01-10 07:01:34 +00:00
|
|
|
getBackend = id
|
|
|
|
|
|
|
|
instance HasBackend Socket where
|
2014-01-17 06:55:33 +00:00
|
|
|
initializeBackend _ = return ()
|
2014-01-10 07:01:34 +00:00
|
|
|
getBackend sock = Backend (return ()) (sClose sock) (Socket.sendAll sock) recvAll
|
|
|
|
where recvAll n = B.concat `fmap` loop n
|
|
|
|
where loop 0 = return []
|
|
|
|
loop left = do
|
|
|
|
r <- Socket.recv sock left
|
|
|
|
liftM (r:) (loop (left - B.length r))
|
|
|
|
|
|
|
|
instance HasBackend Handle where
|
2014-01-17 06:55:33 +00:00
|
|
|
initializeBackend handle = hSetBuffering handle NoBuffering
|
2014-01-10 07:01:34 +00:00
|
|
|
getBackend handle = Backend (hFlush handle) (hClose handle) (B.hPut handle) (B.hGet handle)
|