packages feed

haskell-xmpp-2.0.0: src/Network/XMPP/Helpers.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Network.XMPP.Helpers
-- Copyright   :  (c) Dmitry Astapov, 2006
-- License     :  BSD-style (see the file LICENSE)
-- Copyright   :  (c) riskbook, 2020
-- SPDX-License-Identifier:  BSD3
--
-- Maintainer  :  Dmitry Astapov <dastapov@gmail.com>
-- Stability   :  experimental
-- Portability :  portable
--
-- Various "connection helpers" that let user obtain a handle to pass to 'initiateStream'
--
-----------------------------------------------------------------------------

module Network.XMPP.Helpers
  ( connectViaHttpProxy
  , connectViaTcp
  , openStreamFile
  ) where

import System.IO (Handle, hPutStrLn, hPutStr, hGetLine, openFile, IOMode(..))
import Control.Monad (void, when)

import Network.BSD (getHostByName, hostAddresses)
import qualified Data.Text as T

import Network.Socket
import Control.Concurrent (threadDelay, forkIO)
import Control.Monad.Trans (liftIO)
import Network.XMPP.Utils

-- | Connect to XMPP server on specified host \/ port
connectViaTcp :: T.Text -- ^ Server (hostname) to connect to
              -> Int     -- ^ Port to connect to
              -> IO Handle
connectViaTcp server port = do
  host <- getHostByName $ T.unpack server
  sock <- socket AF_INET Stream 0
  setSocketOption sock KeepAlive 1
  let sockAddress = SockAddrInet (fromIntegral port) $ head $ hostAddresses host
  connect sock sockAddress
  socketToHandle sock ReadWriteMode

-- | Connect to XMPP server on specified host \/ port
--  via HTTP 1.0 proxy
connectViaHttpProxy :: Show a => HostName -> Integer -> T.Text -> a -> IO Handle
connectViaHttpProxy proxyServer proxyPort server port = do
  let hints = defaultHints
        { addrFlags = [AI_NUMERICHOST, AI_NUMERICSERV]
        , addrSocketType = Stream
        }
  addr:_ <- getAddrInfo (Just hints) (Just proxyServer) (Just $ show proxyPort)
  sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
  h <- socketToHandle sock ReadWriteMode
  hPutStrLn h $ unlines
    [ concat ["CONNECT ", T.unpack server, ":", show port, " HTTP/1.0"]
    , "Connection: Keep-Alive"
    ]
  dropHeaders h
  void $ liftIO $ forkIO $ pinger h
  return h
 where
  dropHeaders h = do
    l <- hGetLine h
    debugIO $ "Got: " ++ l
    when (words l /= []) $ dropHeaders h
  pinger h = hPutStr h " " >> threadDelay (30 * (10 ^ (6 :: Int))) >> pinger h

-- | Open file with pre-captured server-to-client XMPP stream. For debugging
openStreamFile :: FilePath -> IO Handle
openStreamFile fname = openFile fname ReadMode