hw-prelude-0.0.1.1: src/HaskellWorks/IO/Network/Port.hs
module HaskellWorks.IO.Network.Port
( randomPort,
reserveRandomPort,
portInUse,
) where
import Control.Exception
import Control.Monad (Monad (..), MonadFail (..))
import Control.Monad.IO.Class
import Control.Monad.Trans.Resource
import Data.Bool
import Data.Either
import Data.Function
import Network.Socket
-- | Return a random available port on a specified host address
randomPort :: ()
=> MonadIO m
=> MonadFail m
=> HostAddress
-> m PortNumber
randomPort hostAddress = do
sock <- liftIO $ socket AF_INET Stream defaultProtocol
-- Allow the port to be reused immediately after the socket is closed
liftIO $ setSocketOption sock ReuseAddr 1
liftIO $ bind sock $ SockAddrInet defaultPort hostAddress
SockAddrInet port _ <- liftIO $ getSocketName sock
liftIO $ close sock
return port
reserveRandomPort :: ()
=> MonadFail m
=> MonadResource m
=> HostAddress
-> m (ReleaseKey, PortNumber)
reserveRandomPort hostAddress = do
sock <- liftIO $ socket AF_INET Stream defaultProtocol
liftIO $ setSocketOption sock ReuseAddr 1
liftIO $ bind sock $ SockAddrInet defaultPort hostAddress
SockAddrInet port _ <- liftIO $ getSocketName sock
releaseKey <- register $ close sock
return (releaseKey, port)
-- | Check if a port is in use on a specified host address
portInUse :: ()
=> MonadIO m
=> HostAddress
-> PortNumber
-> m Bool
portInUse hostAddress pn = do
sock <- liftIO $ socket AF_INET Stream defaultProtocol
liftIO $ setSocketOption sock ReuseAddr 1
result <- liftIO $ try @SomeException $ bind sock (SockAddrInet pn hostAddress)
liftIO $ close sock
return $ either (const False) (const True) result