{-# LANGUAGE OverloadedStrings #-} -- | Simple functions to run TCP clients and servers. module Network.Run.TCP ( runTCPClient , runTCPServer ) where import Control.Concurrent (forkFinally) import qualified Control.Exception as E import Control.Monad (forever, void) import Network.Socket -- | Running a TCP client with a connected socket. runTCPClient :: HostName -> ServiceName -> (Socket -> IO a) -> IO a runTCPClient host port client = withSocketsDo $ do addr <- resolve E.bracket (open addr) (\sock -> gracefulClose sock 5000) client where resolve = do let hints = defaultHints { addrSocketType = Stream } head <$> getAddrInfo (Just hints) (Just host) (Just port) open addr = do sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) connect sock $ addrAddress addr return sock -- | Running a TCP server with an accepted socket and its peer name. runTCPServer :: Maybe HostName -> ServiceName -> (Socket -> SockAddr -> IO a) -> IO a runTCPServer mhost port server = withSocketsDo $ do addr <- resolve E.bracket (open addr) close loop where resolve = do let hints = defaultHints { addrFlags = [AI_PASSIVE] , addrSocketType = Stream } head <$> getAddrInfo (Just hints) mhost (Just port) open addr = do sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) setSocketOption sock ReuseAddr 1 withFdSocket sock $ setCloseOnExecIfNeeded bind sock $ addrAddress addr listen sock 1024 return sock loop sock = forever $ do (conn, peer) <- accept sock void $ forkFinally (server conn peer) (const $ gracefulClose conn 5000)