epoll-0.1: examples/Server.hs
module Main where
import System.Linux.EpollM
import System.Posix.IO
import System.Posix.Types
import System.Environment
import System.IO
import Data.Maybe
import Text.Printf
import Control.Monad
import Control.Monad.Trans
import System.Posix.Signals
import Network.Socket
main :: IO ()
main = getAndVerifyArgs >>= start . head
start :: String -> IO ()
start p = runEpollBig_ $ do
defaultDispatchLoop_ readRequest
ai <- liftIO $ getAddrInfo (Just (defaultHints {addrFlags = [AI_PASSIVE]}))
Nothing
(Just p)
let serveraddr = head ai
-- create server socket
sock <- liftIO $ socket (addrFamily serveraddr) Stream defaultProtocol
liftIO $ setSocketOption sock ReuseAddr 1
-- bind it to the address we're listening to
liftIO $ bindSocket sock (addrAddress serveraddr)
liftIO $ printf "Listening at port %s\n" p
-- start listening for connection requests max. connection requests waiting
-- to be accepted = 5 (max. queue size)
liftIO $ listen sock 256
-- Ignore broken pipes
liftIO $ installHandler sigPIPE Ignore Nothing
-- accept connection requests (CTRL-C to abort)
forever $ do
(connsock, clientaddr) <- liftIO $ accept sock
procRequest connsock clientaddr
where
procRequest :: Socket -> SockAddr -> Epoll ()
procRequest sock' _ = do
let fd = Fd $ fdSocket sock'
liftIO $ setFdOption fd NonBlockingRead True
add sock' [inEvent, peerCloseEvent, oneShotEvent] fd
return ()
readRequest :: Event Socket -> Epoll ()
readRequest e = fork_ $ do
let et = eventType e
fd = eventFd e
liftIO $ printf "event=%s, fd=%s\n" (show et) (show fd)
if et =~ peerCloseEvent
then do liftIO $ putStrLn "peer closed"
delete (eventDesc e)
liftIO $ sClose (eventRef e)
else do (s, _) <- liftIO $ fdRead fd 2048
modify [inEvent, peerCloseEvent, oneShotEvent] (eventDesc e)
liftIO $ printf "readRequest: %s\n" s
getAndVerifyArgs :: IO [String]
getAndVerifyArgs = do
args <- getArgs
when (length args /= 1)
(error "Usage: Server <port>")
return args