module Aws.Network where

import Data.Maybe
import Control.Exception
import Network.BSD (getProtocolNumber)
import Network.Socket
import System.Timeout

-- Make a good guess if a host is reachable.
hostAvailable :: String -> IO Bool
hostAvailable :: ServiceName -> IO Bool
hostAvailable ServiceName
h = do
  Socket
sock <- ServiceName -> IO ProtocolNumber
getProtocolNumber ServiceName
"tcp" IO ProtocolNumber -> (ProtocolNumber -> IO Socket) -> IO Socket
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Family -> SocketType -> ProtocolNumber -> IO Socket
socket Family
AF_INET SocketType
Stream
  SockAddr
addr <- (AddrInfo -> SockAddr
addrAddress (AddrInfo -> SockAddr)
-> ([AddrInfo] -> AddrInfo) -> [AddrInfo] -> SockAddr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [AddrInfo] -> AddrInfo
forall a. HasCallStack => [a] -> a
head) ([AddrInfo] -> SockAddr) -> IO [AddrInfo] -> IO SockAddr
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Maybe AddrInfo
-> Maybe ServiceName -> Maybe ServiceName -> IO [AddrInfo]
getAddrInfo (AddrInfo -> Maybe AddrInfo
forall a. a -> Maybe a
Just (AddrInfo
defaultHints { addrFlags = [ AI_PASSIVE ] } )) (ServiceName -> Maybe ServiceName
forall a. a -> Maybe a
Just ServiceName
h) (ServiceName -> Maybe ServiceName
forall a. a -> Maybe a
Just ServiceName
"80")
  case SockAddr
addr of
    remote :: SockAddr
remote@(SockAddrInet PortNumber
_ HostAddress
_) -> do
      Bool
v <- IO Bool -> (SomeException -> IO Bool) -> IO Bool
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch (Int -> IO () -> IO (Maybe ())
forall a. Int -> IO a -> IO (Maybe a)
timeout Int
100000 (Socket -> SockAddr -> IO ()
connect Socket
sock SockAddr
remote) IO (Maybe ()) -> (Maybe () -> IO Bool) -> IO Bool
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> IO Bool) -> (Maybe () -> Bool) -> Maybe () -> IO Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe () -> Bool
forall a. Maybe a -> Bool
isJust)
                 (\(SomeException
_ :: SomeException) -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False)
      Socket -> IO ()
close Socket
sock
      Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
v
    SockAddr
_ -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False