-- |-- Module : Network.TLS.Backend-- License : BSD-style-- Maintainer : Vincent Hanquez <vincent@snarc.org>-- Stability : experimental-- Portability : unknown---- A Backend represents a unified way to do IO on different-- types without burdening our calling API with multiple-- ways to initialize a new context.---- Typically, a backend provides:-- * 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
import System.IO (Handle, hSetBuffering, BufferMode(..), hFlush, hClose)
-- | 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 -> IOByteString-- ^ Receive specified number of bytes from the connection.
}
class HasBackenda where
initializeBackend :: a -> IO()getBackend :: a -> Backend
instance HasBackendBackend where
initializeBackend _ = return()getBackend = id
instance HasBackendSocket where
initializeBackend _ = return()getBackendsock = Backend (return()) (sClosesock) (Socket.sendAllsock) recvAll
where recvAlln = B.concat`fmap`loopn
where loop0 = return []
loopleft = do
r <- Socket.recvsockleft
if B.nullr
then return []
else liftM (r:) (loop (left-B.lengthr))
instance HasBackendHandle where
initializeBackendhandle = hSetBufferinghandleNoBufferinggetBackendhandle = Backend (hFlushhandle) (hClosehandle) (B.hPuthandle) (B.hGethandle)