epoll-0.2: examples/Server.hs
module Main where
import System.Linux.Epoll
import System.Posix.Types
import System.Environment
import System.IO
import Data.Maybe
import Text.Printf
import Control.Concurrent
import Control.Monad
import System.Posix.Signals
import Network.Socket
import Network.HTTP.Base
import Network.HTTP.Headers
import System.Time
main :: IO ()
main = getAndVerifyArgs >>= start . head
start :: String -> IO ()
start p = do
epoll <- createRuntime (fromJust . toSize $ 8192)
ai <- getAddrInfo (Just (defaultHints {addrFlags = [AI_PASSIVE]}))
Nothing
(Just p)
let serveraddr = head ai
-- create server socket
sock <- socket (addrFamily serveraddr) Stream defaultProtocol
setSocketOption sock ReuseAddr 1
-- bind it to the address we're listening to
bindSocket sock (addrAddress serveraddr)
printf "Listening at port %s\n" p
-- start listening for connection requests max. connection requests waiting
-- to be accepted = 5 (max. queue size)
listen sock 256
-- Ignore broken pipes
installHandler sigPIPE Ignore Nothing
-- accept connection requests (CTRL-C to abort)
forever $ do
(connsock, clientaddr) <- accept sock
procRequest epoll connsock clientaddr
shutdownRuntime epoll
where
procRequest :: Runtime -> Socket -> SockAddr -> IO ThreadId
procRequest r sock' _ = forkIO $ do
let fd = Fd $ fdSocket sock'
withIBuffer r fd $ \ib -> do
header <- readBuffer ib >>=
return . parseRequestHead . takeWhile ("" /=) . breakLines
case header of
Left e -> print $ "caught error: " ++ (show e)
Right _ -> do
now <- getClockTime
let ts = show . calendarTimeToString . toUTCTime $ now
rs = response ts
withOBuffer r fd $ \ob -> do
writeBuffer ob (show rs)
writeBuffer ob (rspBody rs)
sClose sock'
getAndVerifyArgs :: IO [String]
getAndVerifyArgs = do
args <- getArgs
when (length args /= 1)
(error "Usage: Server <port>")
return args
breakLines :: String -> [String]
breakLines str = pre : case rest of
'\r':'\n':suf -> breakLines suf
'\r':suf -> breakLines suf
'\n':suf -> breakLines suf
_ -> []
where
(pre, rest) = break (flip elem "\n\r") str
response :: String -> Response String
response s = Response (2, 0, 0) "OK"
[Header HdrContentLength (show . length $ s)] s