module Network.Hadoop.Socket
( S.Socket
, S.SockAddr(..)
, runTcp
, connectSocket
, newSocket
, closeSocket
) where
import Control.Applicative ((<$>))
import Control.Monad.Catch (MonadMask, bracket, bracketOnError)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Hadoop.Types
import qualified Data.Text as T
import Network (PortID(PortNumber))
import qualified Network.Socket as S
import Network.Socks5 (defaultSocksConf, socksConnectWith)
runTcp :: (MonadMask m, MonadIO m) => Maybe SocksProxy -> Endpoint -> (S.Socket -> m a) -> m a
runTcp Nothing = runTcp'
runTcp (Just proxy) = runSocks proxy
runTcp' :: (MonadMask m, MonadIO m) => Endpoint -> (S.Socket -> m a) -> m a
runTcp' endpoint = bracket
(liftIO $ fst <$> connectSocket endpoint)
(liftIO . closeSocket)
runSocks :: (MonadMask m, MonadIO m) => SocksProxy -> Endpoint -> (S.Socket -> m a) -> m a
runSocks proxy endpoint = bracket
(liftIO $ socksConnectWith proxyConf host port)
(liftIO . closeSocket)
where
proxyConf = defaultSocksConf (T.unpack $ epHost proxy)
(fromIntegral $ epPort proxy)
host = T.unpack $ epHost endpoint
port = PortNumber $ fromIntegral $ epPort endpoint
connectSocket :: Endpoint -> IO (S.Socket, S.SockAddr)
connectSocket endpoint = do
(addr:_) <- S.getAddrInfo (Just hints) (Just host) (Just port)
bracketOnError (newSocket addr) closeSocket $ \sock -> do
let sockAddr = S.addrAddress addr
S.connect sock sockAddr
return (sock, sockAddr)
where
host = T.unpack (epHost endpoint)
port = show (epPort endpoint)
hints = S.defaultHints { S.addrFlags = [S.AI_ADDRCONFIG]
, S.addrSocketType = S.Stream }
newSocket :: S.AddrInfo -> IO S.Socket
newSocket addr = S.socket (S.addrFamily addr)
(S.addrSocketType addr)
(S.addrProtocol addr)
closeSocket :: S.Socket -> IO ()
closeSocket = S.sClose