module Network.HTTP.Lucu.SocketLike
( SocketLike(..)
)
where
#if defined(HAVE_SSL)
import Control.Exception
#endif
import qualified Network.Socket as So
import Network.HTTP.Lucu.HandleLike
#if defined(HAVE_SSL)
import qualified OpenSSL.Session as SSL
import Prelude hiding (catch)
import Prelude.Unicode
#endif
import qualified System.IO as I
class (HandleLike (Handle s)) ⇒ SocketLike s where
type Handle s ∷ ★
accept ∷ s → IO (Handle s, So.SockAddr)
socketPort ∷ s → IO So.PortNumber
instance SocketLike So.Socket where
type Handle So.Socket = I.Handle
accept soSelf
= do (soPeer, addr) ← So.accept soSelf
hPeer ← So.socketToHandle soPeer I.ReadWriteMode
return (hPeer, addr)
socketPort = So.socketPort
#if defined(HAVE_SSL)
instance SocketLike (SSL.SSLContext, So.Socket) where
type Handle (SSL.SSLContext, So.Socket) = SSL.SSL
accept (ctx, soSelf)
= do (soPeer, addr) ← So.accept soSelf
ssl ← SSL.connection ctx soPeer
handshake ssl addr `catch` next ssl addr
where
handshake ∷ SSL.SSL → So.SockAddr → IO (SSL.SSL, So.SockAddr)
handshake ssl addr
= do SSL.accept ssl
return (ssl, addr)
next ∷ SSL.SSL
→ So.SockAddr
→ SSL.SomeSSLException
→ IO (SSL.SSL, So.SockAddr)
next ssl addr e
= do I.hPutStrLn I.stderr
$ "Lucu: failed to accept an SSL connection from "
⧺ show addr
⧺ ":"
I.hPutStrLn I.stderr
$ show e
SSL.shutdown ssl SSL.Bidirectional
accept (ctx, soSelf)
socketPort = So.socketPort ∘ snd
#endif