{-# LANGUAGE Rank2Types #-} {-# LANGUAGE TypeFamilies #-} -- | This module exports facilities allowing you to safely obtain, use and -- release TLS-secured TCP connections within a /Pipes/ pipeline, by relying on -- @pipes-safe@. -- -- This module is meant to be used together with "Pipes.Network.TCP.TLS", and it -- overrides some functions from "Network.Simple.TCP" so that they support -- 'P.MonadSafe'. Additionally, it also exports pipes that establish a -- TLS-secured TCP connection and interact with it unidirectionally, in a -- streaming fashion at once. -- -- You are encouraged to use this module together with "Pipes.Network.TCP.TLS" -- and "Network.Simple.TCP.TLS" as follows: -- -- @ -- import qualified "Network.Simple.TCP.TLS" as TLS hiding (connect, serve, listen, accept) -- import qualified "Pipes.Network.TCP.TLS" as TLS -- import qualified "Pipes.Network.TCP.TLS.Safe" as TLS -- @ module Pipes.Network.TCP.TLS.Safe ( -- * @MonadSafe@-compatible upgrades -- $network-simple-upgrades connect , serve , listen , accept -- * Streaming -- ** Client side -- $client-streaming , fromConnect , toConnect -- ** Server side -- $server-streaming , fromServe , toServe ) where import Control.Monad (forever) import Data.ByteString (ByteString) import qualified Network.Simple.TCP.TLS as S import Network.TLS (contextClose) import Pipes import Pipes.Network.TCP.Safe (listen) import Pipes.Network.TCP.TLS (fromContext, toContext) import qualified Pipes.Safe as P -------------------------------------------------------------------------------- -- $network-simple-upgrades -- -- The following functions are analogous versions of those exported by -- "Network.Simple.TCP.TLS", but compatible with 'P.MonadSafe'. -- | Like 'Network.Simple.TCP.TLS.connect' from "Network.Simple.TCP.TLS", but -- compatible with 'P.MonadSafe'. connect :: P.MonadSafe m => S.ClientParams -> S.HostName -> S.ServiceName -> ((S.Context, S.SockAddr) -> m r) -> m r connect cs host port k = P.bracket (S.connectTls cs host port) (liftIO . contextClose . fst) (S.useTls k) -- | Like 'Network.Simple.TCP.TLS.serve' from "Network.Simple.TCP.TLS", but -- compatible with 'P.MonadSafe'. serve :: P.MonadSafe m => S.ServerParams -> S.HostPreference -> S.ServiceName -> ((S.Context, S.SockAddr) -> IO ()) -> m r serve ss hp port k = do listen hp port $ \(lsock,_) -> do forever $ S.acceptFork ss lsock k -- | Like 'Network.Simple.TCP.TLS.accept' from "Network.Simple.TCP.TLS", but -- compatible with 'P.MonadSafe'. accept :: P.MonadSafe m => S.ServerParams -> S.Socket -> ((S.Context, S.SockAddr) -> m r) -> m r accept ss lsock k = P.bracket (S.acceptTls ss lsock) (liftIO . contextClose . fst) (S.useTls k) {-# INLINABLE accept #-} -------------------------------------------------------------------------------- -- $client-streaming -- -- The following proxies allow you to easily connect to a TLS-secured TCP server -- and immediately interact with it in a streaming fashion, all at once, instead -- of having to perform the individual steps separately. -------------------------------------------------------------------------------- -- | Connect to a TLS-secured TCP server and send downstream the decrypted bytes -- received from the remote end. -- -- Up to @16384@ decrypted bytes will be received at once. The TLS connection is -- automatically renegotiated if a /ClientHello/ message is received. -- -- If the remote peer closes its side of the connection of EOF is reached, this -- proxy returns. -- -- The connection is closed when done or in case of exceptions. fromConnect :: P.MonadSafe m => S.ClientParams -- ^TLS settings. -> S.HostName -> S.ServiceName -- ^Server service port. -> Producer' ByteString m () fromConnect cs host port = do connect cs host port $ \(ctx,_) -> do fromContext ctx -- | Connects to a TLS-secured TCP server, then repeatedly encrypts and sends to -- the remote end the bytes received from upstream. -- -- The connection is properly closed when done or in case of exceptions. toConnect :: P.MonadSafe m => S.ClientParams -- ^TLS settings. -> S.HostName -- ^Server host name. -> S.ServiceName -- ^Server service port. -> Consumer' ByteString m () toConnect cs hp port = do connect cs hp port $ \(ctx,_) -> toContext ctx -------------------------------------------------------------------------------- -- $server-streaming -- -- The following proxies allow you to easily run a TLS-secured TCP server and -- immediately interact with incoming connections in a streaming fashion, all at -- once, instead of having to perform the individual steps separately. -------------------------------------------------------------------------------- -- | Binds a listening TCP socket, accepts a single TLS-secured connection and -- sends downstream any decrypted bytes received from the remote end. -- -- Up to @16384@ decrypted bytes will be received at once. The TLS connection is -- automatically renegotiated if a /ClientHello/ message is received. -- -- If the remote peer closes its side of the connection of EOF is reached, this -- proxy returns. -- -- Both the listening and connection sockets are closed when done or in case of -- exceptions. fromServe :: P.MonadSafe m => S.ServerParams -- ^TLS settings. -> S.HostPreference -- ^Preferred host to bind. -> S.ServiceName -- ^Service port to bind. -> Producer' ByteString m () fromServe ss hp port = do listen hp port $ \(lsock,_) -> do accept ss lsock $ \(ctx,_) -> do fromContext ctx -- | Binds a listening TCP socket, accepts a single TLS-secured connection, -- and repeatedly sends to the remote end any bytes received from upstream. -- -- If the remote peer closes its side of the connection, this proxy returns. -- -- Both the listening and connection sockets are closed when done or in case of -- exceptions. toServe :: P.MonadSafe m => S.ServerParams -- ^TLS settings. -> S.HostPreference -- ^Preferred host to bind. -> S.ServiceName -- ^Service port to bind. -> Consumer' ByteString m r toServe ss hp port = do listen hp port $ \(lsock,_) -> do accept ss lsock $ \(ctx,_) -> do toContext ctx