{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Network.Simple.TCP.TLS (
serve
, S.listen
, accept
, acceptFork
, newDefaultServerParams
, makeServerParams
, connect
, connectOverSOCKS5
, newDefaultClientParams
, makeClientParams
, recv
, send
, sendLazy
, useTls
, useTlsThenClose
, useTlsThenCloseFork
, connectTls
, connectTlsOverSOCKS5
, acceptTls
, makeClientContext
, makeServerContext
, NS.withSocketsDo
, S.HostPreference(..)
, NS.HostName
, NS.ServiceName
, NS.Socket
, NS.SockAddr
, T.Context
, T.ClientParams
, T.ServerParams
, T.Credential
, credentialLoadX509
) where
import Control.Concurrent (ThreadId, forkFinally)
import qualified Control.Exception.Safe as E
import Control.Monad
import Control.Monad.IO.Class (MonadIO, liftIO)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import Data.Default (def)
import Data.List (intersect)
import Data.Maybe (isJust, listToMaybe)
import qualified Data.X509 as X
import qualified Data.X509.CertificateStore as X
import qualified Data.X509.Validation as X
import Foreign.C.Error (Errno(Errno), ePIPE)
import qualified GHC.IO.Exception as Eg
import qualified Network.Simple.TCP as S
import qualified Network.Socket as NS
import qualified Network.TLS as T
import qualified Network.TLS.SessionManager as TSM
import qualified Network.TLS.Extra as TE
import System.X509 (getSystemCertificateStore)
newDefaultClientParams
:: MonadIO m
=> X.ServiceID
-> m T.ClientParams
newDefaultClientParams :: forall (m :: * -> *). MonadIO m => ServiceID -> m ClientParams
newDefaultClientParams ServiceID
sid = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
CertificateStore
cs <- IO CertificateStore
getSystemCertificateStore
SessionManager
sm <- Config -> IO SessionManager
TSM.newSessionManager Config
TSM.defaultConfig
let cp0 :: ClientParams
cp0 = ServiceID -> [Credential] -> CertificateStore -> ClientParams
makeClientParams ServiceID
sid [] CertificateStore
cs
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ ClientParams
cp0
{ clientShared :: Shared
T.clientShared = (ClientParams -> Shared
T.clientShared ClientParams
cp0)
{ sharedSessionManager :: SessionManager
T.sharedSessionManager = SessionManager
sm }
}
makeClientParams
:: X.ServiceID
-> [T.Credential]
-> X.CertificateStore
-> T.ClientParams
makeClientParams :: ServiceID -> [Credential] -> CertificateStore -> ClientParams
makeClientParams ([Char]
hn, ByteString
sp) [Credential]
creds CertificateStore
cStore =
([Char] -> ByteString -> ClientParams
T.defaultParamsClient [Char]
hn ByteString
sp)
{ clientUseServerNameIndication :: Bool
T.clientUseServerNameIndication = Bool
True
, clientSupported :: Supported
T.clientSupported = forall a. Default a => a
def
{ supportedVersions :: [Version]
T.supportedVersions = [Version
T.TLS13, Version
T.TLS12, Version
T.TLS11]
, supportedCiphers :: [Cipher]
T.supportedCiphers = [Cipher]
TE.ciphersuite_default
, supportedSecureRenegotiation :: Bool
T.supportedSecureRenegotiation = Bool
True
, supportedClientInitiatedRenegotiation :: Bool
T.supportedClientInitiatedRenegotiation = Bool
True }
, clientShared :: Shared
T.clientShared = forall a. Default a => a
def { sharedCAStore :: CertificateStore
T.sharedCAStore = CertificateStore
cStore }
, clientHooks :: ClientHooks
T.clientHooks = forall a. Default a => a
def
{ onServerCertificate :: OnServerCertificate
T.onServerCertificate = OnServerCertificate
X.validateDefault
, onCertificateRequest :: OnCertificateRequest
T.onCertificateRequest = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([CertificateType], Maybe [HashAndSignatureAlgorithm],
[DistinguishedName])
-> Maybe Credential
findCredential }
}
where
findCredential
:: ([T.CertificateType],
Maybe [T.HashAndSignatureAlgorithm],
[X.DistinguishedName])
-> Maybe (X.CertificateChain, X.PrivKey)
findCredential :: ([CertificateType], Maybe [HashAndSignatureAlgorithm],
[DistinguishedName])
-> Maybe Credential
findCredential ([CertificateType]
_, Maybe [HashAndSignatureAlgorithm]
_, [DistinguishedName]
dns) = forall a. [a] -> Maybe a
listToMaybe (forall a. (a -> Bool) -> [a] -> [a]
filter forall {b}. (CertificateChain, b) -> Bool
isSubject [Credential]
creds)
where
isSubject :: (CertificateChain, b) -> Bool
isSubject (X.CertificateChain [SignedExact Certificate]
cc, b
_) =
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\SignedExact Certificate
c -> (Certificate -> DistinguishedName
X.certSubjectDN forall b c a. (b -> c) -> (a -> b) -> a -> c
. SignedExact Certificate -> Certificate
X.getCertificate) SignedExact Certificate
c forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [DistinguishedName]
dns) [SignedExact Certificate]
cc
makeServerParams
:: T.Credential
-> Maybe X.CertificateStore
-> T.ServerParams
makeServerParams :: Credential -> Maybe CertificateStore -> ServerParams
makeServerParams Credential
cred Maybe CertificateStore
ycStore = forall a. Default a => a
def
{ serverWantClientCert :: Bool
T.serverWantClientCert = forall a. Maybe a -> Bool
isJust Maybe CertificateStore
ycStore
, serverShared :: Shared
T.serverShared = forall a. Default a => a
def
{ sharedCredentials :: Credentials
T.sharedCredentials = [Credential] -> Credentials
T.Credentials [Credential
cred] }
, serverCACertificates :: [SignedExact Certificate]
T.serverCACertificates = []
, serverSupported :: Supported
T.serverSupported = forall a. Default a => a
def
{ supportedVersions :: [Version]
T.supportedVersions = [Version
T.TLS13, Version
T.TLS12, Version
T.TLS11]
, supportedCiphers :: [Cipher]
T.supportedCiphers = [Cipher]
TE.ciphersuite_strong
, supportedSession :: Bool
T.supportedSession = Bool
True
, supportedSecureRenegotiation :: Bool
T.supportedSecureRenegotiation = Bool
True
, supportedClientInitiatedRenegotiation :: Bool
T.supportedClientInitiatedRenegotiation = Bool
False }
, serverHooks :: ServerHooks
T.serverHooks = forall a. Default a => a
def
{ onClientCertificate :: CertificateChain -> IO CertificateUsage
T.onClientCertificate = CertificateChain -> IO CertificateUsage
clientCertsCheck
, onCipherChoosing :: Version -> [Cipher] -> Cipher
T.onCipherChoosing = Version -> [Cipher] -> Cipher
chooseCipher }
}
where
clientCertsCheck :: X.CertificateChain -> IO T.CertificateUsage
clientCertsCheck :: CertificateChain -> IO CertificateUsage
clientCertsCheck CertificateChain
certs = case Maybe CertificateStore
ycStore of
Maybe CertificateStore
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return CertificateUsage
T.CertificateUsageAccept
Just CertificateStore
cs -> do
let checks :: ValidationChecks
checks = ValidationChecks
X.defaultChecks { checkFQHN :: Bool
X.checkFQHN = Bool
False }
[FailedReason]
es <- HashALG
-> ValidationHooks -> ValidationChecks -> OnServerCertificate
X.validate HashALG
X.HashSHA256 ValidationHooks
X.defaultHooks ValidationChecks
checks CertificateStore
cs forall a. Default a => a
def ([Char]
"",ByteString
"") CertificateChain
certs
case [FailedReason]
es of
[] -> forall (f :: * -> *) a. Applicative f => a -> f a
pure CertificateUsage
T.CertificateUsageAccept
[FailedReason]
errs' -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (CertificateRejectReason -> CertificateUsage
T.CertificateUsageReject ([Char] -> CertificateRejectReason
T.CertificateRejectOther
([Char]
"Unacceptable client cert: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show [FailedReason]
errs')))
chooseCipher :: T.Version -> [T.Cipher] -> T.Cipher
chooseCipher :: Version -> [Cipher] -> Cipher
chooseCipher Version
_ [Cipher]
cCiphs = forall a. [a] -> a
head (forall a. Eq a => [a] -> [a] -> [a]
intersect [Cipher]
TE.ciphersuite_strong [Cipher]
cCiphs)
newDefaultServerParams
:: MonadIO m
=> T.Credential
-> m T.ServerParams
newDefaultServerParams :: forall (m :: * -> *). MonadIO m => Credential -> m ServerParams
newDefaultServerParams Credential
cred = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
SessionManager
sm <- Config -> IO SessionManager
TSM.newSessionManager Config
TSM.defaultConfig
let sp0 :: ServerParams
sp0 = Credential -> Maybe CertificateStore -> ServerParams
makeServerParams Credential
cred forall a. Maybe a
Nothing
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ ServerParams
sp0
{ serverShared :: Shared
T.serverShared = (ServerParams -> Shared
T.serverShared ServerParams
sp0)
{ sharedSessionManager :: SessionManager
T.sharedSessionManager = SessionManager
sm }
}
serve
:: MonadIO m
=> T.ServerParams
-> S.HostPreference
-> S.ServiceName
-> ((T.Context, S.SockAddr) -> IO ())
-> m ()
serve :: forall (m :: * -> *).
MonadIO m =>
ServerParams
-> HostPreference
-> [Char]
-> ((Context, SockAddr) -> IO ())
-> m ()
serve ServerParams
ss HostPreference
hp [Char]
port (Context, SockAddr) -> IO ()
k = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
forall (m :: * -> *) r.
(MonadIO m, MonadMask m) =>
HostPreference -> [Char] -> ((Socket, SockAddr) -> m r) -> m r
S.listen HostPreference
hp [Char]
port forall a b. (a -> b) -> a -> b
$ \(Socket
lsock,SockAddr
_) -> do
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
MonadIO m =>
ServerParams
-> Socket -> ((Context, SockAddr) -> IO ()) -> m ThreadId
acceptFork ServerParams
ss Socket
lsock (Context, SockAddr) -> IO ()
k
accept
:: (MonadIO m, E.MonadMask m)
=> T.ServerParams
-> S.Socket
-> ((T.Context, S.SockAddr) -> m r)
-> m r
accept :: forall (m :: * -> *) r.
(MonadIO m, MonadMask m) =>
ServerParams -> Socket -> ((Context, SockAddr) -> m r) -> m r
accept ServerParams
ss Socket
lsock (Context, SockAddr) -> m r
k = forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
E.bracket (forall (m :: * -> *).
MonadIO m =>
ServerParams -> Socket -> m (Context, SockAddr)
acceptTls ServerParams
ss Socket
lsock)
(forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. Context -> IO ()
T.contextClose forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)
(forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
((Context, SockAddr) -> m a) -> (Context, SockAddr) -> m a
useTls (Context, SockAddr) -> m r
k)
acceptFork
:: MonadIO m
=> T.ServerParams
-> S.Socket
-> ((T.Context, S.SockAddr) -> IO ())
-> m ThreadId
acceptFork :: forall (m :: * -> *).
MonadIO m =>
ServerParams
-> Socket -> ((Context, SockAddr) -> IO ()) -> m ThreadId
acceptFork ServerParams
ss Socket
lsock (Context, SockAddr) -> IO ()
k = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
E.bracketOnError (forall (m :: * -> *).
MonadIO m =>
ServerParams -> Socket -> m (Context, SockAddr)
acceptTls ServerParams
ss Socket
lsock)
(Context -> IO ()
T.contextClose forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)
(forall (m :: * -> *).
MonadIO m =>
((Context, SockAddr) -> IO ()) -> (Context, SockAddr) -> m ThreadId
useTlsThenCloseFork (Context, SockAddr) -> IO ()
k)
connect
:: (MonadIO m, E.MonadMask m)
=> T.ClientParams
-> S.HostName
-> S.ServiceName
-> ((T.Context, S.SockAddr) -> m r)
-> m r
connect :: forall (m :: * -> *) r.
(MonadIO m, MonadMask m) =>
ClientParams
-> [Char] -> [Char] -> ((Context, SockAddr) -> m r) -> m r
connect ClientParams
cs [Char]
host [Char]
port (Context, SockAddr) -> m r
k = forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
E.bracket (forall (m :: * -> *).
MonadIO m =>
ClientParams -> [Char] -> [Char] -> m (Context, SockAddr)
connectTls ClientParams
cs [Char]
host [Char]
port)
(forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. Context -> IO ()
T.contextClose forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)
(forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
((Context, SockAddr) -> m a) -> (Context, SockAddr) -> m a
useTls (Context, SockAddr) -> m r
k)
connectOverSOCKS5
:: (MonadIO m, E.MonadMask m)
=> S.HostName
-> S.ServiceName
-> T.ClientParams
-> S.HostName
-> S.ServiceName
-> ((T.Context, S.SockAddr, S.SockAddr) -> m r)
-> m r
connectOverSOCKS5 :: forall (m :: * -> *) r.
(MonadIO m, MonadMask m) =>
[Char]
-> [Char]
-> ClientParams
-> [Char]
-> [Char]
-> ((Context, SockAddr, SockAddr) -> m r)
-> m r
connectOverSOCKS5 [Char]
phn [Char]
psn ClientParams
cs [Char]
dhn [Char]
dsn (Context, SockAddr, SockAddr) -> m r
k = do
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
E.bracket (forall (m :: * -> *).
MonadIO m =>
[Char]
-> [Char]
-> ClientParams
-> [Char]
-> [Char]
-> m (Context, SockAddr, SockAddr)
connectTlsOverSOCKS5 [Char]
phn [Char]
psn ClientParams
cs [Char]
dhn [Char]
dsn)
(\(Context
ctx, SockAddr
_, SockAddr
_) -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (Context -> IO ()
T.contextClose Context
ctx))
(\(Context
ctx, SockAddr
paddr, SockAddr
daddr) ->
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
((Context, SockAddr) -> m a) -> (Context, SockAddr) -> m a
useTls (\(Context, SockAddr)
_ -> (Context, SockAddr, SockAddr) -> m r
k (Context
ctx, SockAddr
paddr, SockAddr
daddr))
(Context
ctx, SockAddr
paddr))
connectTls
:: MonadIO m
=> T.ClientParams
-> S.HostName
-> S.ServiceName
-> m (T.Context, S.SockAddr)
connectTls :: forall (m :: * -> *).
MonadIO m =>
ClientParams -> [Char] -> [Char] -> m (Context, SockAddr)
connectTls ClientParams
cs [Char]
host [Char]
port = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
E.bracketOnError
(forall (m :: * -> *).
MonadIO m =>
[Char] -> [Char] -> m (Socket, SockAddr)
S.connectSock [Char]
host [Char]
port)
(forall (m :: * -> *). MonadIO m => Socket -> m ()
S.closeSock forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)
(\(Socket
sock, SockAddr
addr) -> do
Context
ctx <- forall (m :: * -> *).
MonadIO m =>
ClientParams -> Socket -> m Context
makeClientContext ClientParams
cs Socket
sock
forall (m :: * -> *) a. Monad m => a -> m a
return (Context
ctx, SockAddr
addr))
connectTlsOverSOCKS5
:: MonadIO m
=> S.HostName
-> S.ServiceName
-> T.ClientParams
-> S.HostName
-> S.ServiceName
-> m (T.Context, S.SockAddr, S.SockAddr)
connectTlsOverSOCKS5 :: forall (m :: * -> *).
MonadIO m =>
[Char]
-> [Char]
-> ClientParams
-> [Char]
-> [Char]
-> m (Context, SockAddr, SockAddr)
connectTlsOverSOCKS5 [Char]
phn [Char]
psn ClientParams
cs [Char]
dhn [Char]
dsn = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
E.bracketOnError
(forall (m :: * -> *).
MonadIO m =>
[Char] -> [Char] -> m (Socket, SockAddr)
S.connectSock [Char]
phn [Char]
psn)
(forall (m :: * -> *). MonadIO m => Socket -> m ()
S.closeSock forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)
(\(Socket
psock, SockAddr
paddr) -> do
SockAddr
daddr <- forall (m :: * -> *).
MonadIO m =>
Socket -> [Char] -> [Char] -> m SockAddr
S.connectSockSOCKS5 Socket
psock [Char]
dhn [Char]
dsn
Context
ctx <- forall (m :: * -> *).
MonadIO m =>
ClientParams -> Socket -> m Context
makeClientContext ClientParams
cs Socket
psock
forall (m :: * -> *) a. Monad m => a -> m a
return (Context
ctx, SockAddr
paddr, SockAddr
daddr))
makeClientContext :: MonadIO m => T.ClientParams -> S.Socket -> m T.Context
makeClientContext :: forall (m :: * -> *).
MonadIO m =>
ClientParams -> Socket -> m Context
makeClientContext ClientParams
params Socket
sock = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) backend params.
(MonadIO m, HasBackend backend, TLSParams params) =>
backend -> params -> m Context
T.contextNew Socket
sock ClientParams
params
acceptTls
:: MonadIO m
=> T.ServerParams
-> S.Socket
-> m (T.Context, S.SockAddr)
acceptTls :: forall (m :: * -> *).
MonadIO m =>
ServerParams -> Socket -> m (Context, SockAddr)
acceptTls ServerParams
sp Socket
lsock = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
E.bracketOnError
(Socket -> IO (Socket, SockAddr)
NS.accept Socket
lsock)
(forall (m :: * -> *). MonadIO m => Socket -> m ()
S.closeSock forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)
(\(Socket
sock, SockAddr
addr) -> do
Context
ctx <- forall (m :: * -> *).
MonadIO m =>
ServerParams -> Socket -> m Context
makeServerContext ServerParams
sp Socket
sock
forall (m :: * -> *) a. Monad m => a -> m a
return (Context
ctx, SockAddr
addr))
makeServerContext :: MonadIO m => T.ServerParams -> S.Socket -> m T.Context
makeServerContext :: forall (m :: * -> *).
MonadIO m =>
ServerParams -> Socket -> m Context
makeServerContext ServerParams
params Socket
sock = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) backend params.
(MonadIO m, HasBackend backend, TLSParams params) =>
backend -> params -> m Context
T.contextNew Socket
sock ServerParams
params
useTls
:: (MonadIO m, E.MonadMask m)
=> ((T.Context, S.SockAddr) -> m a)
-> ((T.Context, S.SockAddr) -> m a)
useTls :: forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
((Context, SockAddr) -> m a) -> (Context, SockAddr) -> m a
useTls (Context, SockAddr) -> m a
k conn :: (Context, SockAddr)
conn@(Context
ctx,SockAddr
_) = forall (m :: * -> *) a b c. MonadMask m => m a -> m b -> m c -> m c
E.bracket_ (forall (m :: * -> *). MonadIO m => Context -> m ()
T.handshake Context
ctx)
(forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Context -> IO ()
silentBye Context
ctx)
((Context, SockAddr) -> m a
k (Context, SockAddr)
conn)
useTlsThenClose
:: (MonadIO m, E.MonadMask m)
=> ((T.Context, S.SockAddr) -> m a)
-> ((T.Context, S.SockAddr) -> m a)
useTlsThenClose :: forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
((Context, SockAddr) -> m a) -> (Context, SockAddr) -> m a
useTlsThenClose (Context, SockAddr) -> m a
k conn :: (Context, SockAddr)
conn@(Context
ctx,SockAddr
_) = do
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
((Context, SockAddr) -> m a) -> (Context, SockAddr) -> m a
useTls (Context, SockAddr) -> m a
k (Context, SockAddr)
conn forall (m :: * -> *) a b. MonadMask m => m a -> m b -> m a
`E.finally` forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (Context -> IO ()
T.contextClose Context
ctx)
useTlsThenCloseFork
:: MonadIO m
=> ((T.Context, S.SockAddr) -> IO ())
-> ((T.Context, S.SockAddr) -> m ThreadId)
useTlsThenCloseFork :: forall (m :: * -> *).
MonadIO m =>
((Context, SockAddr) -> IO ()) -> (Context, SockAddr) -> m ThreadId
useTlsThenCloseFork (Context, SockAddr) -> IO ()
k conn :: (Context, SockAddr)
conn@(Context
ctx,SockAddr
_) = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
forall a. IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
forkFinally (forall (m :: * -> *) a b c. MonadMask m => m a -> m b -> m c -> m c
E.bracket_ (forall (m :: * -> *). MonadIO m => Context -> m ()
T.handshake Context
ctx) (Context -> IO ()
silentBye Context
ctx) ((Context, SockAddr) -> IO ()
k (Context, SockAddr)
conn))
(\Either SomeException ()
eu -> Context -> IO ()
T.contextClose Context
ctx forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
E.throwIO forall (m :: * -> *) a. Monad m => a -> m a
return Either SomeException ()
eu)
recv :: MonadIO m => T.Context -> m (Maybe B.ByteString)
recv :: forall (m :: * -> *). MonadIO m => Context -> m (Maybe ByteString)
recv Context
ctx = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
(e -> m a) -> m a -> m a
E.handle (\case TLSError
T.Error_EOF -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
TLSError
e -> forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
E.throwM TLSError
e)
(do ByteString
bs <- forall (m :: * -> *). MonadIO m => Context -> m ByteString
T.recvData Context
ctx
if ByteString -> Bool
B.null ByteString
bs
then forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
else forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> Maybe a
Just ByteString
bs))
{-# INLINABLE recv #-}
send :: MonadIO m => T.Context -> B.ByteString -> m ()
send :: forall (m :: * -> *). MonadIO m => Context -> ByteString -> m ()
send Context
ctx = \ByteString
bs -> forall (m :: * -> *). MonadIO m => Context -> ByteString -> m ()
T.sendData Context
ctx (ByteString -> ByteString
BL.fromStrict ByteString
bs)
{-# INLINABLE send #-}
sendLazy :: MonadIO m => T.Context -> BL.ByteString -> m ()
sendLazy :: forall (m :: * -> *). MonadIO m => Context -> ByteString -> m ()
sendLazy = forall (m :: * -> *). MonadIO m => Context -> ByteString -> m ()
T.sendData
{-# INLINE sendLazy #-}
credentialLoadX509
:: MonadIO m
=> FilePath
-> FilePath
-> m (Either String T.Credential)
credentialLoadX509 :: forall (m :: * -> *).
MonadIO m =>
[Char] -> [Char] -> m (Either [Char] Credential)
credentialLoadX509 [Char]
cert [Char]
key = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> IO (Either [Char] Credential)
T.credentialLoadX509 [Char]
cert [Char]
key
silentBye :: T.Context -> IO ()
silentBye :: Context -> IO ()
silentBye Context
ctx = do
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
E.catch (forall (m :: * -> *). MonadIO m => Context -> m ()
T.bye Context
ctx) forall a b. (a -> b) -> a -> b
$ \IOException
e -> case IOException
e of
Eg.IOError{ ioe_type :: IOException -> IOErrorType
Eg.ioe_type = IOErrorType
Eg.ResourceVanished
, ioe_errno :: IOException -> Maybe CInt
Eg.ioe_errno = Just CInt
ioe
} | CInt -> Errno
Errno CInt
ioe forall a. Eq a => a -> a -> Bool
== Errno
ePIPE
-> forall (m :: * -> *) a. Monad m => a -> m a
return ()
IOException
_ -> forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
E.throwIO IOException
e