From 985974c264804ff788b3b5242fef707d4b7fa9a6 Mon Sep 17 00:00:00 2001 From: evuez Date: Mon, 1 Apr 2024 15:17:30 +0200 Subject: Initial commit --- src/Tcp.hs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/Tcp.hs (limited to 'src/Tcp.hs') diff --git a/src/Tcp.hs b/src/Tcp.hs new file mode 100644 index 0000000..d0ee6c9 --- /dev/null +++ b/src/Tcp.hs @@ -0,0 +1,50 @@ +module Tcp (runServer) where + +import Control.Concurrent (forkFinally) +import qualified Control.Exception as E +import Control.Monad (forever, void) +import Intro +import Network.Socket + ( AddrInfoFlag (AI_PASSIVE) + , HostName + , ServiceName + , Socket + , SocketOption (ReuseAddr) + , SocketType (Stream) + , accept + , addrAddress + , addrFlags + , addrSocketType + , bind + , close + , defaultHints + , getAddrInfo + , gracefulClose + , listen + , openSocket + , setCloseOnExecIfNeeded + , setSocketOption + , withFdSocket + , withSocketsDo + ) + +runServer :: Maybe HostName -> ServiceName -> (Socket -> IO a) -> IO a +runServer host port server = withSocketsDo $ do + addr <- resolve + E.bracket (open addr) close go + where + resolve = do + let hints = defaultHints{addrFlags = [AI_PASSIVE], addrSocketType = Stream} + head <$> getAddrInfo (Just hints) host (Just port) + open addr = E.bracketOnError (openSocket addr) close $ \sock -> do + setSocketOption sock ReuseAddr 1 + withFdSocket sock setCloseOnExecIfNeeded + bind sock $ addrAddress addr + listen sock 1024 + pure sock + go :: Socket -> IO a + go sock = forever + $ E.bracketOnError (accept sock) (close . fst) + $ \(conn, _peer) -> + void + $ forkFinally (server conn) (const $ gracefulClose conn 5000) -- cgit v1.2.3