module Network.Salvia.Core.Network where import Control.Concurrent (forkIO) import Control.Monad import Network.Socket import System.IO -------- application independent networking ----------------------------------- type Server a = Handle -> SockAddr -> IO a {- Start a listening TCP server on the specified address/port combination and handle every connection with a custom handler. -} server :: HostAddress -> PortNumber -> Int -> Server a -> IO () server addr port backlog handler = do sock <- socket AF_INET Stream 0 setSocketOption sock ReuseAddr 1 bindSocket sock $ SockAddrInet port addr listen sock backlog acceptLoop sock handler {- Accept connections on the listening socket and pass execution to the application specific connection handler. -} acceptLoop :: Socket -> Server s -> IO () acceptLoop sock handler = do forever $ do (sock', addr) <- accept sock forkIO $ do handle <- socketToHandle sock' ReadWriteMode -- TODO: Using NoBuffering here may crash the entire program (GHC -- runtime?) when processing more requests than just a few: hSetBuffering handle (BlockBuffering (Just (64*1024))) handler handle addr -- We can probably just ignore exceptions from hClose, but this for the -- moment I am interested whether this even happens. hClose handle -- e <- try (hClose handle) -- case e of -- Left ex -> putStrLn ("Failure during hClose: " ++ show (ex :: IOException)) -- Right _ -> return () putStrLn "quiting"