module Network.HTTP.Lucu.Httpd
( runHttpd
)
where
import Control.Concurrent
import Control.Exception
import Control.Monad
import Control.Monad.Unicode
import Data.Maybe
import Network.BSD
import Network.Socket
import Network.HTTP.Lucu.Config
import Network.HTTP.Lucu.Dispatcher
import Network.HTTP.Lucu.Interaction
import Network.HTTP.Lucu.RequestReader
import Network.HTTP.Lucu.ResponseWriter
import Network.HTTP.Lucu.SocketLike as SL
import Prelude.Unicode
runHttpd ∷ HostMapper α ⇒ Config → α → IO ()
runHttpd cnf hm
= do let launchers
= catMaybes
[ do addr ← cnfServerV4Addr cnf
return ( launchListener =≪ listenOn AF_INET addr (cnfServerPort cnf)
)
, do addr ← cnfServerV6Addr cnf
return ( launchListener =≪ listenOn AF_INET6 addr (cnfServerPort cnf)
)
#if defined(HAVE_SSL)
, do scnf ← cnfSSLConfig cnf
addr ← cnfServerV4Addr cnf
return ( do so ← listenOn AF_INET addr (sslServerPort scnf)
launchListener (sslContext scnf, so)
)
, do scnf ← cnfSSLConfig cnf
addr ← cnfServerV6Addr cnf
return ( do so ← listenOn AF_INET6 addr (sslServerPort scnf)
launchListener (sslContext scnf, so)
)
#endif
]
sequence_ launchers
waitForever
where
launchListener ∷ SocketLike s ⇒ s → IO ()
launchListener so
= do p ← SL.socketPort so
void ∘ forkIO $ httpLoop p so
listenOn ∷ Family → HostName → ServiceName → IO Socket
listenOn fam host srv
= do proto ← getProtocolNumber "tcp"
let hints = defaultHints {
addrFlags = [AI_PASSIVE]
, addrFamily = fam
, addrSocketType = Stream
, addrProtocol = proto
}
addrs ← getAddrInfo (Just hints) (Just host) (Just srv)
let addr = head addrs
bracketOnError
(socket (addrFamily addr)
(addrSocketType addr)
(addrProtocol addr))
sClose
(\ sock →
do setSocketOption sock ReuseAddr 1
bindSocket sock (addrAddress addr)
listen sock maxListenQueue
return sock
)
httpLoop ∷ SocketLike s ⇒ PortNumber → s → IO ()
httpLoop port so
= do (h, addr) ← SL.accept so
tQueue ← mkInteractionQueue
readerTID ← forkIO $ requestReader cnf hm h port addr tQueue
_writerTID ← forkIO $ responseWriter cnf h tQueue readerTID
httpLoop port so
waitForever ∷ IO ()
waitForever = forever $ threadDelay 1000000