{-|
Module      : Util.Net
Description : Utilities for Network IO.

License     : BSD3
Maintainer  : The Idris Community.
-}
module Util.Net (listenOnLocalhost, listenOnLocalhostAnyPort) where

import Control.Exception (bracketOnError)
import Network.Socket
-- Copied from upstream impl of listenOn
-- bound to localhost interface instead of iNADDR_ANY
listenOnLocalhost :: PortNumber -> IO Socket
listenOnLocalhost :: PortNumber -> IO Socket
listenOnLocalhost PortNumber
port = do
    let hints :: AddrInfo
hints = AddrInfo
defaultHints { addrSocketType :: SocketType
addrSocketType = SocketType
Stream }
    AddrInfo
localhost:[AddrInfo]
_ <- Maybe AddrInfo -> Maybe HostName -> Maybe HostName -> IO [AddrInfo]
getAddrInfo (forall a. a -> Maybe a
Just AddrInfo
hints) (forall a. a -> Maybe a
Just HostName
"127.0.0.1") (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> HostName
show PortNumber
port)
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracketOnError
      (Family -> SocketType -> ProtocolNumber -> IO Socket
socket Family
AF_INET SocketType
Stream ProtocolNumber
defaultProtocol)
      (Socket -> IO ()
close)
      (\Socket
sock -> do
          Socket -> SocketOption -> Int -> IO ()
setSocketOption Socket
sock SocketOption
ReuseAddr Int
1
          Socket -> SockAddr -> IO ()
bind Socket
sock (AddrInfo -> SockAddr
addrAddress AddrInfo
localhost)
          Socket -> Int -> IO ()
listen Socket
sock Int
maxListenQueue
          forall (m :: * -> *) a. Monad m => a -> m a
return Socket
sock
      )

listenOnLocalhostAnyPort :: IO (Socket, PortNumber)
listenOnLocalhostAnyPort :: IO (Socket, PortNumber)
listenOnLocalhostAnyPort = do
    let hints :: AddrInfo
hints = AddrInfo
defaultHints { addrSocketType :: SocketType
addrSocketType = SocketType
Stream }
    AddrInfo
localhost:[AddrInfo]
_ <- Maybe AddrInfo -> Maybe HostName -> Maybe HostName -> IO [AddrInfo]
getAddrInfo (forall a. a -> Maybe a
Just AddrInfo
hints) (forall a. a -> Maybe a
Just HostName
"127.0.0.1") (forall a. a -> Maybe a
Just HostName
"0")
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracketOnError
      (Family -> SocketType -> ProtocolNumber -> IO Socket
socket Family
AF_INET SocketType
Stream ProtocolNumber
defaultProtocol)
      (Socket -> IO ()
close)
      (\Socket
sock -> do
          Socket -> SocketOption -> Int -> IO ()
setSocketOption Socket
sock SocketOption
ReuseAddr Int
1
          Socket -> SockAddr -> IO ()
bind Socket
sock (AddrInfo -> SockAddr
addrAddress AddrInfo
localhost)
          Socket -> Int -> IO ()
listen Socket
sock Int
maxListenQueue
          PortNumber
port <- Socket -> IO PortNumber
socketPort Socket
sock
          forall (m :: * -> *) a. Monad m => a -> m a
return (Socket
sock, PortNumber
port)
      )