module Network.Socket.ByteString.Extended
( module Network.Socket
, module Network.Socket.ByteString
, Sink(..)
, Source(..)
, withActiveSocket
, withPassiveSocket
, toNetworkByteOrder
) where
import Control.Error
import Control.Monad.IO.Class (liftIO)
import Data.Binary.Put (putWord32be, runPut)
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Lazy.Char8 as Lazy (toStrict)
import Data.IP (IPv4, fromHostAddress,
toHostAddress)
import Network.Socket hiding (recv, recvFrom, send,
sendTo)
import Network.Socket.ByteString
import System.Timeout
data Sink = Sink IPv4 PortNumber
data Source = Source IPv4 (Maybe PortNumber)
withActiveSocket :: Sink
-> (PortNumber -> ExceptT String IO ())
-> (Socket -> IO ())
-> ExceptT String IO ()
withActiveSocket (Sink i p) onListen onConnected = do
liftIO $ return withSocketsDo
sock <- liftIO $ socket AF_INET Stream defaultProtocol
onListen p
liftIO $ connect sock (SockAddrInet p (toHostAddress i))
liftIO $ onConnected sock
liftIO $ sClose sock
withPassiveSocket :: Source
-> (PortNumber -> ExceptT String IO ())
-> (Socket -> IO ())
-> ExceptT String IO ()
withPassiveSocket (Source i maybeP) onListen onConnected = do
liftIO $ return withSocketsDo
sock <- liftIO $ openListenSocket (fromMaybe aNY_PORT maybeP)
p <- liftIO $ socketPort sock
onListen p
accepted <- liftIO $ timeout 10000000 $ accept sock
case accepted of
Just (con, SockAddrInet _ client)
| client == toHostAddress i -> liftIO $ do onConnected con
sClose con
| otherwise -> do liftIO $ sClose con
throwE ( "Expected connection from host "
++ show (fromHostAddress client)
++ ", not from " ++ show i ++". Aborting…\n" )
_ -> throwE ( "Timeout when waiting for other party to connect on port "
++ show p ++ "…\n")
liftIO $ sClose sock
openListenSocket :: PortNumber -> IO Socket
openListenSocket p = do
sock <- socket AF_INET Stream defaultProtocol
bind sock (SockAddrInet p iNADDR_ANY)
listen sock 1
return sock
toNetworkByteOrder :: Integral a => a -> ByteString
toNetworkByteOrder = Lazy.toStrict . runPut . putWord32be . fromIntegral