{-# LANGUAGE ScopedTypeVariables #-}{-# LANGUAGE TypeSynonymInstances #-}------------------------------------------------------------------------------- |-- Module : Network.TCP-- Copyright : See LICENSE file-- License : BSD---- Maintainer : Ganesh Sittampalam <ganesh@earth.li>-- Stability : experimental-- Portability : non-portable (not tested)---- Some utility functions for working with the Haskell @network@ package. Mostly-- for internal use by the @Network.HTTP@ code.-------------------------------------------------------------------------------moduleNetwork.TCP(Connection ,EndPoint (..),openTCPPort ,isConnectedTo ,openTCPConnection ,socketConnection ,isTCPConnectedTo ,HandleStream ,HStream (..),StreamHooks (..),nullHooks ,setStreamHooks ,getStreamHooks ,hstreamToConnection )whereimportNetwork.Socket(Socket,SocketOption(KeepAlive),SocketType(Stream),connect,shutdown,ShutdownCmd(..),setSocketOption,getPeerName,socket,Family(AF_UNSPEC),defaultProtocol,getAddrInfo,defaultHints,addrFamily,withSocketsDo,addrSocketType,addrAddress)importqualifiedNetwork.Socket(close)importqualifiedNetwork.Stream asStream(Stream (readBlock ,readLine ,writeBlock ,close ,closeOnEnd ))importNetwork.Stream (ConnError (..),Result ,failWith ,failMisc )importNetwork.BufferType importNetwork.HTTP.Base (catchIO )importNetwork.Socket(socketToHandle)importData.Char(toLower)importData.Word(Word8)importControl.ConcurrentimportControl.Exception(IOException,bracketOnError,try)importControl.Monad(liftM,when)importSystem.IO(Handle,hFlush,IOMode(..),hClose)importSystem.IO.Error(isEOFError)importqualifiedData.ByteStringasStrictimportqualifiedData.ByteString.LazyasLazy----------------------------------------------------------------------------------- TCP Connections ------------------------------------------------------------------------------------------------- | The 'Connection' newtype is a wrapper that allows us to make-- connections an instance of the Stream class, without GHC extensions.-- While this looks sort of like a generic reference to the transport-- layer it is actually TCP specific, which can be seen in the-- implementation of the 'Stream Connection' instance.newtypeConnection =Connection (HandleStream String)newtypeHandleStream a =HandleStream {HandleStream a -> MVar (Conn a) getRef ::MVar(Conn a )}dataEndPoint =EndPoint {EndPoint -> String epHost ::String,EndPoint -> Int epPort ::Int}instanceEqEndPoint whereEndPoint String host1 Int port1 == :: EndPoint -> EndPoint -> Bool ==EndPoint String host2 Int port2 =(Char -> Char) -> String -> String forall a b. (a -> b) -> [a] -> [b] mapChar -> Char toLowerString host1 String -> String -> Bool forall a. Eq a => a -> a -> Bool ==(Char -> Char) -> String -> String forall a b. (a -> b) -> [a] -> [b] mapChar -> Char toLowerString host2 Bool -> Bool -> Bool &&Int port1 Int -> Int -> Bool forall a. Eq a => a -> a -> Bool ==Int port2 dataConn a =MkConn {Conn a -> Socket connSock ::!Socket,Conn a -> Handle connHandle ::Handle,Conn a -> BufferOp a connBuffer ::BufferOp a ,Conn a -> Maybe a connInput ::Maybea ,Conn a -> EndPoint connEndPoint ::EndPoint ,Conn a -> Maybe (StreamHooks a) connHooks ::Maybe(StreamHooks a ),Conn a -> Bool connCloseEOF ::Bool-- True => close socket upon reaching end-of-stream.}|ConnClosed deriving(Conn a -> Conn a -> Bool (Conn a -> Conn a -> Bool) -> (Conn a -> Conn a -> Bool) -> Eq (Conn a) forall a. Eq a => Conn a -> Conn a -> Bool forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a /= :: Conn a -> Conn a -> Bool $c/= :: forall a. Eq a => Conn a -> Conn a -> Bool == :: Conn a -> Conn a -> Bool $c== :: forall a. Eq a => Conn a -> Conn a -> Bool Eq)hstreamToConnection ::HandleStream String->Connection hstreamToConnection :: HandleStream String -> Connection hstreamToConnection HandleStream String h =HandleStream String -> Connection Connection HandleStream String h connHooks' ::Conn a ->Maybe(StreamHooks a )connHooks' :: Conn a -> Maybe (StreamHooks a) connHooks' ConnClosed {}=Maybe (StreamHooks a) forall a. Maybe a NothingconnHooks' Conn a x =Conn a -> Maybe (StreamHooks a) forall a. Conn a -> Maybe (StreamHooks a) connHooks Conn a x -- all of these are post-op hooksdataStreamHooks ty =StreamHooks {StreamHooks ty -> (ty -> String) -> Result ty -> IO () hook_readLine ::(ty ->String)->Result ty ->IO(),StreamHooks ty -> (ty -> String) -> Int -> Result ty -> IO () hook_readBlock ::(ty ->String)->Int->Result ty ->IO(),StreamHooks ty -> (ty -> String) -> ty -> Result () -> IO () hook_writeBlock ::(ty ->String)->ty ->Result ()->IO(),StreamHooks ty -> IO () hook_close ::IO(),StreamHooks ty -> String hook_name ::String-- hack alert: name of the hook itself.}instanceEqty =>Eq(StreamHooks ty )where== :: StreamHooks ty -> StreamHooks ty -> Bool (==)StreamHooks ty _StreamHooks ty _=Bool TruenullHooks ::StreamHooks ty nullHooks :: StreamHooks ty nullHooks =StreamHooks :: forall ty. ((ty -> String) -> Result ty -> IO ()) -> ((ty -> String) -> Int -> Result ty -> IO ()) -> ((ty -> String) -> ty -> Result () -> IO ()) -> IO () -> String -> StreamHooks ty StreamHooks {hook_readLine :: (ty -> String) -> Result ty -> IO () hook_readLine =\ty -> String _Result ty _->() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return(),hook_readBlock :: (ty -> String) -> Int -> Result ty -> IO () hook_readBlock =\ty -> String _Int _Result ty _->() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return(),hook_writeBlock :: (ty -> String) -> ty -> Result () -> IO () hook_writeBlock =\ty -> String _ty _Result () _->() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return(),hook_close :: IO () hook_close =() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return(),hook_name :: String hook_name =String ""}setStreamHooks ::HandleStream ty ->StreamHooks ty ->IO()setStreamHooks :: HandleStream ty -> StreamHooks ty -> IO () setStreamHooks HandleStream ty h StreamHooks ty sh =MVar (Conn ty) -> (Conn ty -> IO (Conn ty)) -> IO () forall a. MVar a -> (a -> IO a) -> IO () modifyMVar_(HandleStream ty -> MVar (Conn ty) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream ty h )(\Conn ty c ->Conn ty -> IO (Conn ty) forall (m :: * -> *) a. Monad m => a -> m a returnConn ty c {connHooks :: Maybe (StreamHooks ty) connHooks =StreamHooks ty -> Maybe (StreamHooks ty) forall a. a -> Maybe a JustStreamHooks ty sh })getStreamHooks ::HandleStream ty ->IO(Maybe(StreamHooks ty ))getStreamHooks :: HandleStream ty -> IO (Maybe (StreamHooks ty)) getStreamHooks HandleStream ty h =MVar (Conn ty) -> IO (Conn ty) forall a. MVar a -> IO a readMVar(HandleStream ty -> MVar (Conn ty) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream ty h )IO (Conn ty) -> (Conn ty -> IO (Maybe (StreamHooks ty))) -> IO (Maybe (StreamHooks ty)) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>=Maybe (StreamHooks ty) -> IO (Maybe (StreamHooks ty)) forall (m :: * -> *) a. Monad m => a -> m a return(Maybe (StreamHooks ty) -> IO (Maybe (StreamHooks ty))) -> (Conn ty -> Maybe (StreamHooks ty)) -> Conn ty -> IO (Maybe (StreamHooks ty)) forall b c a. (b -> c) -> (a -> b) -> a -> c .Conn ty -> Maybe (StreamHooks ty) forall a. Conn a -> Maybe (StreamHooks a) connHooks -- | @HStream@ overloads the use of 'HandleStream's, letting you-- overload the handle operations over the type that is communicated-- across the handle. It comes in handy for @Network.HTTP@ 'Request'-- and 'Response's as the payload representation isn't fixed, but overloaded.---- The library comes with instances for @ByteString@s and @String@, but-- should you want to plug in your own payload representation, defining-- your own @HStream@ instance _should_ be all that it takes.--classBufferType bufType =>HStream bufType whereopenStream ::String->Int->IO(HandleStream bufType )openSocketStream ::String->Int->Socket->IO(HandleStream bufType )readLine ::HandleStream bufType ->IO(Result bufType )readBlock ::HandleStream bufType ->Int->IO(Result bufType )writeBlock ::HandleStream bufType ->bufType ->IO(Result ())close ::HandleStream bufType ->IO()closeQuick ::HandleStream bufType ->IO()closeOnEnd ::HandleStream bufType ->Bool->IO()instanceHStream Strict.ByteStringwhereopenStream :: String -> Int -> IO (HandleStream ByteString) openStream =String -> Int -> IO (HandleStream ByteString) forall ty. BufferType ty => String -> Int -> IO (HandleStream ty) openTCPConnection openSocketStream :: String -> Int -> Socket -> IO (HandleStream ByteString) openSocketStream =String -> Int -> Socket -> IO (HandleStream ByteString) forall ty. BufferType ty => String -> Int -> Socket -> IO (HandleStream ty) socketConnection readBlock :: HandleStream ByteString -> Int -> IO (Result ByteString) readBlock HandleStream ByteString c Int n =HandleStream ByteString -> Int -> IO (Result ByteString) forall a. HStream a => HandleStream a -> Int -> IO (Result a) readBlockBS HandleStream ByteString c Int n readLine :: HandleStream ByteString -> IO (Result ByteString) readLine HandleStream ByteString c =HandleStream ByteString -> IO (Result ByteString) forall a. HStream a => HandleStream a -> IO (Result a) readLineBS HandleStream ByteString c writeBlock :: HandleStream ByteString -> ByteString -> IO (Result ()) writeBlock HandleStream ByteString c ByteString str =HandleStream ByteString -> ByteString -> IO (Result ()) forall a. HandleStream a -> a -> IO (Result ()) writeBlockBS HandleStream ByteString c ByteString str close :: HandleStream ByteString -> IO () close HandleStream ByteString c =HandleStream ByteString -> (ByteString -> Bool) -> Bool -> IO () forall ty. HStream ty => HandleStream ty -> (ty -> Bool) -> Bool -> IO () closeIt HandleStream ByteString c ByteString -> Bool Strict.nullBool TruecloseQuick :: HandleStream ByteString -> IO () closeQuick HandleStream ByteString c =HandleStream ByteString -> (ByteString -> Bool) -> Bool -> IO () forall ty. HStream ty => HandleStream ty -> (ty -> Bool) -> Bool -> IO () closeIt HandleStream ByteString c ByteString -> Bool Strict.nullBool FalsecloseOnEnd :: HandleStream ByteString -> Bool -> IO () closeOnEnd HandleStream ByteString c Bool f =HandleStream ByteString -> Bool -> IO () forall ty. HandleStream ty -> Bool -> IO () closeEOF HandleStream ByteString c Bool f instanceHStream Lazy.ByteStringwhereopenStream :: String -> Int -> IO (HandleStream ByteString) openStream =\String a Int b ->String -> Int -> Bool -> IO (HandleStream ByteString) forall ty. BufferType ty => String -> Int -> Bool -> IO (HandleStream ty) openTCPConnection_ String a Int b Bool TrueopenSocketStream :: String -> Int -> Socket -> IO (HandleStream ByteString) openSocketStream =\String a Int b Socket c ->String -> Int -> Socket -> Bool -> IO (HandleStream ByteString) forall ty. BufferType ty => String -> Int -> Socket -> Bool -> IO (HandleStream ty) socketConnection_ String a Int b Socket c Bool TruereadBlock :: HandleStream ByteString -> Int -> IO (Result ByteString) readBlock HandleStream ByteString c Int n =HandleStream ByteString -> Int -> IO (Result ByteString) forall a. HStream a => HandleStream a -> Int -> IO (Result a) readBlockBS HandleStream ByteString c Int n readLine :: HandleStream ByteString -> IO (Result ByteString) readLine HandleStream ByteString c =HandleStream ByteString -> IO (Result ByteString) forall a. HStream a => HandleStream a -> IO (Result a) readLineBS HandleStream ByteString c writeBlock :: HandleStream ByteString -> ByteString -> IO (Result ()) writeBlock HandleStream ByteString c ByteString str =HandleStream ByteString -> ByteString -> IO (Result ()) forall a. HandleStream a -> a -> IO (Result ()) writeBlockBS HandleStream ByteString c ByteString str close :: HandleStream ByteString -> IO () close HandleStream ByteString c =HandleStream ByteString -> (ByteString -> Bool) -> Bool -> IO () forall ty. HStream ty => HandleStream ty -> (ty -> Bool) -> Bool -> IO () closeIt HandleStream ByteString c ByteString -> Bool Lazy.nullBool TruecloseQuick :: HandleStream ByteString -> IO () closeQuick HandleStream ByteString c =HandleStream ByteString -> (ByteString -> Bool) -> Bool -> IO () forall ty. HStream ty => HandleStream ty -> (ty -> Bool) -> Bool -> IO () closeIt HandleStream ByteString c ByteString -> Bool Lazy.nullBool FalsecloseOnEnd :: HandleStream ByteString -> Bool -> IO () closeOnEnd HandleStream ByteString c Bool f =HandleStream ByteString -> Bool -> IO () forall ty. HandleStream ty -> Bool -> IO () closeEOF HandleStream ByteString c Bool f instanceStream.Stream Connection wherereadBlock :: Connection -> Int -> IO (Result String) readBlock (Connection HandleStream String c )=HandleStream String -> Int -> IO (Result String) forall a. HStream a => HandleStream a -> Int -> IO (Result a) Network.TCP.readBlock HandleStream String c readLine :: Connection -> IO (Result String) readLine (Connection HandleStream String c )=HandleStream String -> IO (Result String) forall a. HStream a => HandleStream a -> IO (Result a) Network.TCP.readLine HandleStream String c writeBlock :: Connection -> String -> IO (Result ()) writeBlock (Connection HandleStream String c )=HandleStream String -> String -> IO (Result ()) forall bufType. HStream bufType => HandleStream bufType -> bufType -> IO (Result ()) Network.TCP.writeBlock HandleStream String c close :: Connection -> IO () close (Connection HandleStream String c )=HandleStream String -> IO () forall bufType. HStream bufType => HandleStream bufType -> IO () Network.TCP.close HandleStream String c closeOnEnd :: Connection -> Bool -> IO () closeOnEnd (Connection HandleStream String c )Bool f =HandleStream String -> Bool -> IO () forall ty. HandleStream ty -> Bool -> IO () Network.TCP.closeEOF HandleStream String c Bool f instanceHStream StringwhereopenStream :: String -> Int -> IO (HandleStream String) openStream =String -> Int -> IO (HandleStream String) forall ty. BufferType ty => String -> Int -> IO (HandleStream ty) openTCPConnection openSocketStream :: String -> Int -> Socket -> IO (HandleStream String) openSocketStream =String -> Int -> Socket -> IO (HandleStream String) forall ty. BufferType ty => String -> Int -> Socket -> IO (HandleStream ty) socketConnection readBlock :: HandleStream String -> Int -> IO (Result String) readBlock HandleStream String ref Int n =HandleStream String -> Int -> IO (Result String) forall a. HStream a => HandleStream a -> Int -> IO (Result a) readBlockBS HandleStream String ref Int n -- This function uses a buffer, at this time the buffer is just 1000 characters.-- (however many bytes this is is left to the user to decypher)readLine :: HandleStream String -> IO (Result String) readLine HandleStream String ref =HandleStream String -> IO (Result String) forall a. HStream a => HandleStream a -> IO (Result a) readLineBS HandleStream String ref -- The 'Connection' object allows no outward buffering,-- since in general messages are serialised in their entirety.writeBlock :: HandleStream String -> String -> IO (Result ()) writeBlock HandleStream String ref String str =HandleStream String -> String -> IO (Result ()) forall a. HandleStream a -> a -> IO (Result ()) writeBlockBS HandleStream String ref String str -- (stringToBuf str)-- Closes a Connection. Connection will no longer-- allow any of the other Stream functions. Notice that a Connection may close-- at any time before a call to this function. This function is idempotent.-- (I think the behaviour here is TCP specific)close :: HandleStream String -> IO () close HandleStream String c =HandleStream String -> (String -> Bool) -> Bool -> IO () forall ty. HStream ty => HandleStream ty -> (ty -> Bool) -> Bool -> IO () closeIt HandleStream String c String -> Bool forall (t :: * -> *) a. Foldable t => t a -> Bool nullBool True-- Closes a Connection without munching the rest of the stream.closeQuick :: HandleStream String -> IO () closeQuick HandleStream String c =HandleStream String -> (String -> Bool) -> Bool -> IO () forall ty. HStream ty => HandleStream ty -> (ty -> Bool) -> Bool -> IO () closeIt HandleStream String c String -> Bool forall (t :: * -> *) a. Foldable t => t a -> Bool nullBool FalsecloseOnEnd :: HandleStream String -> Bool -> IO () closeOnEnd HandleStream String c Bool f =HandleStream String -> Bool -> IO () forall ty. HandleStream ty -> Bool -> IO () closeEOF HandleStream String c Bool f -- | @openTCPPort uri port@ establishes a connection to a remote-- host, using 'getHostByName' which possibly queries the DNS system, hence-- may trigger a network connection.openTCPPort ::String->Int->IOConnection openTCPPort :: String -> Int -> IO Connection openTCPPort String uri Int port =String -> Int -> IO (HandleStream String) forall ty. BufferType ty => String -> Int -> IO (HandleStream ty) openTCPConnection String uri Int port IO (HandleStream String) -> (HandleStream String -> IO Connection) -> IO Connection forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>=Connection -> IO Connection forall (m :: * -> *) a. Monad m => a -> m a return(Connection -> IO Connection) -> (HandleStream String -> Connection) -> HandleStream String -> IO Connection forall b c a. (b -> c) -> (a -> b) -> a -> c .HandleStream String -> Connection Connection -- Add a "persistent" option? Current persistent is default.-- Use "Result" type for synchronous exception reporting?openTCPConnection ::BufferType ty =>String->Int->IO(HandleStream ty )openTCPConnection :: String -> Int -> IO (HandleStream ty) openTCPConnection String uri Int port =String -> Int -> Bool -> IO (HandleStream ty) forall ty. BufferType ty => String -> Int -> Bool -> IO (HandleStream ty) openTCPConnection_ String uri Int port Bool FalseopenTCPConnection_ ::BufferType ty =>String->Int->Bool->IO(HandleStream ty )openTCPConnection_ :: String -> Int -> Bool -> IO (HandleStream ty) openTCPConnection_ String uri Int port Bool stashInput =do-- HACK: uri is sometimes obtained by calling Network.URI.uriRegName, and this includes-- the surrounding square brackets for an RFC 2732 host like [::1]. It's not clear whether-- it should, or whether all call sites should be using something different instead, but-- the simplest short-term fix is to strip any surrounding square brackets here.-- It shouldn't affect any as this is the only situation they can occur - see RFC 3986.letfixedUri :: String fixedUri =caseString uri ofChar '[':(rest :: String rest @(Char c :String _))|String -> Char forall a. [a] -> a lastString rest Char -> Char -> Bool forall a. Eq a => a -> a -> Bool ==Char ']'->ifChar c Char -> Char -> Bool forall a. Eq a => a -> a -> Bool ==Char 'v'Bool -> Bool -> Bool ||Char c Char -> Char -> Bool forall a. Eq a => a -> a -> Bool ==Char 'V'thenString -> String forall a. HasCallStack => String -> a error(String -> String) -> String -> String forall a b. (a -> b) -> a -> b $String "Unsupported post-IPv6 address "String -> String -> String forall a. [a] -> [a] -> [a] ++String uri elseString -> String forall a. [a] -> [a] initString rest String _->String uri -- use withSocketsDo here in case the caller hasn't used it, which would make getAddrInfo fail on Windows-- although withSocketsDo is supposed to wrap the entire program, in practice it is safe to use it locally-- like this as it just does a once-only installation of a shutdown handler to run at program exit,-- rather than actually shutting down after the action[AddrInfo] addrinfos <-IO [AddrInfo] -> IO [AddrInfo] forall a. IO a -> IO a withSocketsDo(IO [AddrInfo] -> IO [AddrInfo]) -> IO [AddrInfo] -> IO [AddrInfo] forall a b. (a -> b) -> a -> b $Maybe AddrInfo -> Maybe String -> Maybe String -> IO [AddrInfo] getAddrInfo(AddrInfo -> Maybe AddrInfo forall a. a -> Maybe a Just(AddrInfo -> Maybe AddrInfo) -> AddrInfo -> Maybe AddrInfo forall a b. (a -> b) -> a -> b $AddrInfo defaultHints{addrFamily :: Family addrFamily=Family AF_UNSPEC,addrSocketType :: SocketType addrSocketType=SocketType Stream})(String -> Maybe String forall a. a -> Maybe a JustString fixedUri )(String -> Maybe String forall a. a -> Maybe a Just(String -> Maybe String) -> (Int -> String) -> Int -> Maybe String forall b c a. (b -> c) -> (a -> b) -> a -> c .Int -> String forall a. Show a => a -> String show(Int -> Maybe String) -> Int -> Maybe String forall a b. (a -> b) -> a -> b $Int port )letconnectAddrInfo :: AddrInfo -> IO (HandleStream ty) connectAddrInfo AddrInfo a =IO Socket -> (Socket -> IO ()) -> (Socket -> IO (HandleStream ty)) -> IO (HandleStream ty) forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c bracketOnError(Family -> SocketType -> ProtocolNumber -> IO Socket socket(AddrInfo -> Family addrFamilyAddrInfo a )SocketType StreamProtocolNumber defaultProtocol)-- acquireSocket -> IO () Network.Socket.close-- release(\Socket s ->doSocket -> SocketOption -> Int -> IO () setSocketOptionSocket s SocketOption KeepAliveInt 1Socket -> SockAddr -> IO () connectSocket s (AddrInfo -> SockAddr addrAddressAddrInfo a )String -> Int -> Socket -> Bool -> IO (HandleStream ty) forall ty. BufferType ty => String -> Int -> Socket -> Bool -> IO (HandleStream ty) socketConnection_ String fixedUri Int port Socket s Bool stashInput )-- try multiple addresses; return Just connected socket or NothingtryAddrInfos :: [AddrInfo] -> IO (Maybe (HandleStream ty)) tryAddrInfos []=Maybe (HandleStream ty) -> IO (Maybe (HandleStream ty)) forall (m :: * -> *) a. Monad m => a -> m a returnMaybe (HandleStream ty) forall a. Maybe a NothingtryAddrInfos (AddrInfo h :[AddrInfo] t )=letnext :: IOException -> IO (Maybe (HandleStream ty)) next =\(IOException _::IOException)->[AddrInfo] -> IO (Maybe (HandleStream ty)) tryAddrInfos [AddrInfo] t inIO (HandleStream ty) -> IO (Either IOException (HandleStream ty)) forall e a. Exception e => IO a -> IO (Either e a) try(AddrInfo -> IO (HandleStream ty) forall ty. BufferType ty => AddrInfo -> IO (HandleStream ty) connectAddrInfo AddrInfo h )IO (Either IOException (HandleStream ty)) -> (Either IOException (HandleStream ty) -> IO (Maybe (HandleStream ty))) -> IO (Maybe (HandleStream ty)) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>=(IOException -> IO (Maybe (HandleStream ty))) -> (HandleStream ty -> IO (Maybe (HandleStream ty))) -> Either IOException (HandleStream ty) -> IO (Maybe (HandleStream ty)) forall a c b. (a -> c) -> (b -> c) -> Either a b -> c eitherIOException -> IO (Maybe (HandleStream ty)) next (Maybe (HandleStream ty) -> IO (Maybe (HandleStream ty)) forall (m :: * -> *) a. Monad m => a -> m a return(Maybe (HandleStream ty) -> IO (Maybe (HandleStream ty))) -> (HandleStream ty -> Maybe (HandleStream ty)) -> HandleStream ty -> IO (Maybe (HandleStream ty)) forall b c a. (b -> c) -> (a -> b) -> a -> c .HandleStream ty -> Maybe (HandleStream ty) forall a. a -> Maybe a Just)case[AddrInfo] addrinfos of[]->String -> IO (HandleStream ty) forall (m :: * -> *) a. MonadFail m => String -> m a failString "openTCPConnection: getAddrInfo returned no address information"-- single AddrInfo; call connectAddrInfo directly so that specific-- exception is thrown in event of failure[AddrInfo ai ]->AddrInfo -> IO (HandleStream ty) forall ty. BufferType ty => AddrInfo -> IO (HandleStream ty) connectAddrInfo AddrInfo ai IO (HandleStream ty) -> (IOException -> IO (HandleStream ty)) -> IO (HandleStream ty) forall a. IO a -> (IOException -> IO a) -> IO a `catchIO` (\IOException e ->String -> IO (HandleStream ty) forall (m :: * -> *) a. MonadFail m => String -> m a fail(String -> IO (HandleStream ty)) -> String -> IO (HandleStream ty) forall a b. (a -> b) -> a -> b $String "openTCPConnection: failed to connect to "String -> String -> String forall a. [a] -> [a] -> [a] ++SockAddr -> String forall a. Show a => a -> String show(AddrInfo -> SockAddr addrAddressAddrInfo ai )String -> String -> String forall a. [a] -> [a] -> [a] ++String ": "String -> String -> String forall a. [a] -> [a] -> [a] ++IOException -> String forall a. Show a => a -> String showIOException e )-- multiple AddrInfos; try each until we get a connection, or run out[AddrInfo] ais ->leterr :: IO a err =String -> IO a forall (m :: * -> *) a. MonadFail m => String -> m a fail(String -> IO a) -> String -> IO a forall a b. (a -> b) -> a -> b $String "openTCPConnection: failed to connect; tried addresses: "String -> String -> String forall a. [a] -> [a] -> [a] ++[SockAddr] -> String forall a. Show a => a -> String show((AddrInfo -> SockAddr) -> [AddrInfo] -> [SockAddr] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmapAddrInfo -> SockAddr addrAddress[AddrInfo] ais )in[AddrInfo] -> IO (Maybe (HandleStream ty)) forall ty. BufferType ty => [AddrInfo] -> IO (Maybe (HandleStream ty)) tryAddrInfos [AddrInfo] ais IO (Maybe (HandleStream ty)) -> (Maybe (HandleStream ty) -> IO (HandleStream ty)) -> IO (HandleStream ty) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>=IO (HandleStream ty) -> (HandleStream ty -> IO (HandleStream ty)) -> Maybe (HandleStream ty) -> IO (HandleStream ty) forall b a. b -> (a -> b) -> Maybe a -> b maybeIO (HandleStream ty) forall a. IO a err HandleStream ty -> IO (HandleStream ty) forall (m :: * -> *) a. Monad m => a -> m a return-- | @socketConnection@, like @openConnection@ but using a pre-existing 'Socket'.socketConnection ::BufferType ty =>String->Int->Socket->IO(HandleStream ty )socketConnection :: String -> Int -> Socket -> IO (HandleStream ty) socketConnection String hst Int port Socket sock =String -> Int -> Socket -> Bool -> IO (HandleStream ty) forall ty. BufferType ty => String -> Int -> Socket -> Bool -> IO (HandleStream ty) socketConnection_ String hst Int port Socket sock Bool False-- Internal function used to control the on-demand streaming of input-- for /lazy/ streams.socketConnection_ ::BufferType ty =>String->Int->Socket->Bool->IO(HandleStream ty )socketConnection_ :: String -> Int -> Socket -> Bool -> IO (HandleStream ty) socketConnection_ String hst Int port Socket sock Bool stashInput =doHandle h <-Socket -> IOMode -> IO Handle socketToHandleSocket sock IOMode ReadWriteModeMaybe ty mb <-caseBool stashInput of{Bool True->(ty -> Maybe ty) -> IO ty -> IO (Maybe ty) forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r liftMty -> Maybe ty forall a. a -> Maybe a Just(IO ty -> IO (Maybe ty)) -> IO ty -> IO (Maybe ty) forall a b. (a -> b) -> a -> b $BufferOp ty -> Handle -> IO ty forall a. BufferOp a -> Handle -> IO a buf_hGetContents BufferOp ty forall bufType. BufferType bufType => BufferOp bufType bufferOps Handle h ;Bool _->Maybe ty -> IO (Maybe ty) forall (m :: * -> *) a. Monad m => a -> m a returnMaybe ty forall a. Maybe a Nothing}letconn :: Conn ty conn =MkConn :: forall a. Socket -> Handle -> BufferOp a -> Maybe a -> EndPoint -> Maybe (StreamHooks a) -> Bool -> Conn a MkConn {connSock :: Socket connSock =Socket sock ,connHandle :: Handle connHandle =Handle h ,connBuffer :: BufferOp ty connBuffer =BufferOp ty forall bufType. BufferType bufType => BufferOp bufType bufferOps ,connInput :: Maybe ty connInput =Maybe ty mb ,connEndPoint :: EndPoint connEndPoint =String -> Int -> EndPoint EndPoint String hst Int port ,connHooks :: Maybe (StreamHooks ty) connHooks =Maybe (StreamHooks ty) forall a. Maybe a Nothing,connCloseEOF :: Bool connCloseEOF =Bool False}MVar (Conn ty) v <-Conn ty -> IO (MVar (Conn ty)) forall a. a -> IO (MVar a) newMVarConn ty conn HandleStream ty -> IO (HandleStream ty) forall (m :: * -> *) a. Monad m => a -> m a return(MVar (Conn ty) -> HandleStream ty forall a. MVar (Conn a) -> HandleStream a HandleStream MVar (Conn ty) v )closeConnection ::HStream a =>HandleStream a ->IOBool->IO()closeConnection :: HandleStream a -> IO Bool -> IO () closeConnection HandleStream a ref IO Bool readL =do-- won't hold onto the lock for the duration-- we are draining it...ToDo: have Connection-- into a shutting-down state so that other-- threads will simply back off if/when attempting-- to also close it.Conn a c <-MVar (Conn a) -> IO (Conn a) forall a. MVar a -> IO a readMVar(HandleStream a -> MVar (Conn a) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream a ref )Conn a -> IO () forall a. Conn a -> IO () closeConn Conn a c IO () -> (IOException -> IO ()) -> IO () forall a. IO a -> (IOException -> IO a) -> IO a `catchIO` (\IOException _->() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return())MVar (Conn a) -> (Conn a -> IO (Conn a)) -> IO () forall a. MVar a -> (a -> IO a) -> IO () modifyMVar_(HandleStream a -> MVar (Conn a) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream a ref )(\Conn a _->Conn a -> IO (Conn a) forall (m :: * -> *) a. Monad m => a -> m a returnConn a forall a. Conn a ConnClosed )where-- Be kind to peer & close gracefully.closeConn :: Conn a -> IO () closeConn Conn a ConnClosed =() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return()closeConn Conn a conn =doletsk :: Socket sk =Conn a -> Socket forall a. Conn a -> Socket connSock Conn a conn Handle -> IO () hFlush(Conn a -> Handle forall a. Conn a -> Handle connHandle Conn a conn )Socket -> ShutdownCmd -> IO () shutdownSocket sk ShutdownCmd ShutdownSendIO Bool -> IO () suck IO Bool readL Handle -> IO () hClose(Conn a -> Handle forall a. Conn a -> Handle connHandle Conn a conn )Socket -> ShutdownCmd -> IO () shutdownSocket sk ShutdownCmd ShutdownReceiveSocket -> IO () Network.Socket.closeSocket sk suck ::IOBool->IO()suck :: IO Bool -> IO () suck IO Bool rd =doBool f <-IO Bool rd ifBool f then() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return()elseIO Bool -> IO () suck IO Bool rd -- | Checks both that the underlying Socket is connected-- and that the connection peer matches the given-- host name (which is recorded locally).isConnectedTo ::Connection ->EndPoint ->IOBoolisConnectedTo :: Connection -> EndPoint -> IO Bool isConnectedTo (Connection HandleStream String conn )EndPoint endPoint =HandleStream String -> EndPoint -> IO Bool forall ty. HandleStream ty -> EndPoint -> IO Bool isTCPConnectedTo HandleStream String conn EndPoint endPoint isTCPConnectedTo ::HandleStream ty ->EndPoint ->IOBoolisTCPConnectedTo :: HandleStream ty -> EndPoint -> IO Bool isTCPConnectedTo HandleStream ty conn EndPoint endPoint =doConn ty v <-MVar (Conn ty) -> IO (Conn ty) forall a. MVar a -> IO a readMVar(HandleStream ty -> MVar (Conn ty) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream ty conn )caseConn ty v ofConn ty ConnClosed ->Bool -> IO Bool forall (m :: * -> *) a. Monad m => a -> m a returnBool FalseConn ty _|Conn ty -> EndPoint forall a. Conn a -> EndPoint connEndPoint Conn ty v EndPoint -> EndPoint -> Bool forall a. Eq a => a -> a -> Bool ==EndPoint endPoint ->IO Bool -> (IOException -> IO Bool) -> IO Bool forall a. IO a -> (IOException -> IO a) -> IO a catchIO (Socket -> IO SockAddr getPeerName(Conn ty -> Socket forall a. Conn a -> Socket connSock Conn ty v )IO SockAddr -> IO Bool -> IO Bool forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >>Bool -> IO Bool forall (m :: * -> *) a. Monad m => a -> m a returnBool True)(IO Bool -> IOException -> IO Bool forall a b. a -> b -> a const(IO Bool -> IOException -> IO Bool) -> IO Bool -> IOException -> IO Bool forall a b. (a -> b) -> a -> b $Bool -> IO Bool forall (m :: * -> *) a. Monad m => a -> m a returnBool False)|Bool otherwise->Bool -> IO Bool forall (m :: * -> *) a. Monad m => a -> m a returnBool FalsereadBlockBS ::HStream a =>HandleStream a ->Int->IO(Result a )readBlockBS :: HandleStream a -> Int -> IO (Result a) readBlockBS HandleStream a ref Int n =HandleStream a -> (Conn a -> IO (Result a)) -> IO (Result a) forall a b. HandleStream a -> (Conn a -> IO (Result b)) -> IO (Result b) onNonClosedDo HandleStream a ref ((Conn a -> IO (Result a)) -> IO (Result a)) -> (Conn a -> IO (Result a)) -> IO (Result a) forall a b. (a -> b) -> a -> b $\Conn a conn ->doResult a x <-HandleStream a -> Int -> IO (Result a) forall a. HStream a => HandleStream a -> Int -> IO (Result a) bufferGetBlock HandleStream a ref Int n IO () -> (StreamHooks a -> IO ()) -> Maybe (StreamHooks a) -> IO () forall b a. b -> (a -> b) -> Maybe a -> b maybe(() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return())(\StreamHooks a h ->StreamHooks a -> (a -> String) -> Int -> Result a -> IO () forall ty. StreamHooks ty -> (ty -> String) -> Int -> Result ty -> IO () hook_readBlock StreamHooks a h (BufferOp a -> a -> String forall a. BufferOp a -> a -> String buf_toStr (BufferOp a -> a -> String) -> BufferOp a -> a -> String forall a b. (a -> b) -> a -> b $Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )Int n Result a x )(Conn a -> Maybe (StreamHooks a) forall a. Conn a -> Maybe (StreamHooks a) connHooks' Conn a conn )Result a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a returnResult a x -- This function uses a buffer, at this time the buffer is just 1000 characters.-- (however many bytes this is is left for the user to decipher)readLineBS ::HStream a =>HandleStream a ->IO(Result a )readLineBS :: HandleStream a -> IO (Result a) readLineBS HandleStream a ref =HandleStream a -> (Conn a -> IO (Result a)) -> IO (Result a) forall a b. HandleStream a -> (Conn a -> IO (Result b)) -> IO (Result b) onNonClosedDo HandleStream a ref ((Conn a -> IO (Result a)) -> IO (Result a)) -> (Conn a -> IO (Result a)) -> IO (Result a) forall a b. (a -> b) -> a -> b $\Conn a conn ->doResult a x <-HandleStream a -> IO (Result a) forall a. HStream a => HandleStream a -> IO (Result a) bufferReadLine HandleStream a ref IO () -> (StreamHooks a -> IO ()) -> Maybe (StreamHooks a) -> IO () forall b a. b -> (a -> b) -> Maybe a -> b maybe(() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return())(\StreamHooks a h ->StreamHooks a -> (a -> String) -> Result a -> IO () forall ty. StreamHooks ty -> (ty -> String) -> Result ty -> IO () hook_readLine StreamHooks a h (BufferOp a -> a -> String forall a. BufferOp a -> a -> String buf_toStr (BufferOp a -> a -> String) -> BufferOp a -> a -> String forall a b. (a -> b) -> a -> b $Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )Result a x )(Conn a -> Maybe (StreamHooks a) forall a. Conn a -> Maybe (StreamHooks a) connHooks' Conn a conn )Result a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a returnResult a x -- The 'Connection' object allows no outward buffering,-- since in general messages are serialised in their entirety.writeBlockBS ::HandleStream a ->a ->IO(Result ())writeBlockBS :: HandleStream a -> a -> IO (Result ()) writeBlockBS HandleStream a ref a b =HandleStream a -> (Conn a -> IO (Result ())) -> IO (Result ()) forall a b. HandleStream a -> (Conn a -> IO (Result b)) -> IO (Result b) onNonClosedDo HandleStream a ref ((Conn a -> IO (Result ())) -> IO (Result ())) -> (Conn a -> IO (Result ())) -> IO (Result ()) forall a b. (a -> b) -> a -> b $\Conn a conn ->doResult () x <-BufferOp a -> Handle -> a -> IO (Result ()) forall a. BufferOp a -> Handle -> a -> IO (Result ()) bufferPutBlock (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )(Conn a -> Handle forall a. Conn a -> Handle connHandle Conn a conn )a b IO () -> (StreamHooks a -> IO ()) -> Maybe (StreamHooks a) -> IO () forall b a. b -> (a -> b) -> Maybe a -> b maybe(() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return())(\StreamHooks a h ->StreamHooks a -> (a -> String) -> a -> Result () -> IO () forall ty. StreamHooks ty -> (ty -> String) -> ty -> Result () -> IO () hook_writeBlock StreamHooks a h (BufferOp a -> a -> String forall a. BufferOp a -> a -> String buf_toStr (BufferOp a -> a -> String) -> BufferOp a -> a -> String forall a b. (a -> b) -> a -> b $Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )a b Result () x )(Conn a -> Maybe (StreamHooks a) forall a. Conn a -> Maybe (StreamHooks a) connHooks' Conn a conn )Result () -> IO (Result ()) forall (m :: * -> *) a. Monad m => a -> m a returnResult () x closeIt ::HStream ty =>HandleStream ty ->(ty ->Bool)->Bool->IO()closeIt :: HandleStream ty -> (ty -> Bool) -> Bool -> IO () closeIt HandleStream ty c ty -> Bool p Bool b =doHandleStream ty -> IO Bool -> IO () forall a. HStream a => HandleStream a -> IO Bool -> IO () closeConnection HandleStream ty c (ifBool b thenHandleStream ty -> IO (Result ty) forall a. HStream a => HandleStream a -> IO (Result a) readLineBS HandleStream ty c IO (Result ty) -> (Result ty -> IO Bool) -> IO Bool forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>=\Result ty x ->caseResult ty x of{Rightty xs ->Bool -> IO Bool forall (m :: * -> *) a. Monad m => a -> m a return(ty -> Bool p ty xs );Result ty _->Bool -> IO Bool forall (m :: * -> *) a. Monad m => a -> m a returnBool True}elseBool -> IO Bool forall (m :: * -> *) a. Monad m => a -> m a returnBool True)Conn ty conn <-MVar (Conn ty) -> IO (Conn ty) forall a. MVar a -> IO a readMVar(HandleStream ty -> MVar (Conn ty) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream ty c )IO () -> (StreamHooks ty -> IO ()) -> Maybe (StreamHooks ty) -> IO () forall b a. b -> (a -> b) -> Maybe a -> b maybe(() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return())(StreamHooks ty -> IO () forall ty. StreamHooks ty -> IO () hook_close )(Conn ty -> Maybe (StreamHooks ty) forall a. Conn a -> Maybe (StreamHooks a) connHooks' Conn ty conn )closeEOF ::HandleStream ty ->Bool->IO()closeEOF :: HandleStream ty -> Bool -> IO () closeEOF HandleStream ty c Bool flg =MVar (Conn ty) -> (Conn ty -> IO (Conn ty)) -> IO () forall a. MVar a -> (a -> IO a) -> IO () modifyMVar_(HandleStream ty -> MVar (Conn ty) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream ty c )(\Conn ty co ->Conn ty -> IO (Conn ty) forall (m :: * -> *) a. Monad m => a -> m a returnConn ty co {connCloseEOF :: Bool connCloseEOF =Bool flg })bufferGetBlock ::HStream a =>HandleStream a ->Int->IO(Result a )bufferGetBlock :: HandleStream a -> Int -> IO (Result a) bufferGetBlock HandleStream a ref Int n =HandleStream a -> (Conn a -> IO (Result a)) -> IO (Result a) forall a b. HandleStream a -> (Conn a -> IO (Result b)) -> IO (Result b) onNonClosedDo HandleStream a ref ((Conn a -> IO (Result a)) -> IO (Result a)) -> (Conn a -> IO (Result a)) -> IO (Result a) forall a b. (a -> b) -> a -> b $\Conn a conn ->docaseConn a -> Maybe a forall a. Conn a -> Maybe a connInput Conn a conn ofJusta c ->dolet(a a ,a b )=BufferOp a -> Int -> a -> (a, a) forall a. BufferOp a -> Int -> a -> (a, a) buf_splitAt (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )Int n a c MVar (Conn a) -> (Conn a -> IO (Conn a)) -> IO () forall a. MVar a -> (a -> IO a) -> IO () modifyMVar_(HandleStream a -> MVar (Conn a) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream a ref )(\Conn a co ->Conn a -> IO (Conn a) forall (m :: * -> *) a. Monad m => a -> m a returnConn a co {connInput :: Maybe a connInput =a -> Maybe a forall a. a -> Maybe a Justa b })Result a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a return(a -> Result a forall (m :: * -> *) a. Monad m => a -> m a returna a )Maybe a _->doIO (Result a) -> (IOException -> IO (Result a)) -> IO (Result a) forall a. IO a -> (IOException -> IO a) -> IO a catchIO (BufferOp a -> Handle -> Int -> IO a forall a. BufferOp a -> Handle -> Int -> IO a buf_hGet (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )(Conn a -> Handle forall a. Conn a -> Handle connHandle Conn a conn )Int n IO a -> (a -> IO (Result a)) -> IO (Result a) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>=Result a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a return(Result a -> IO (Result a)) -> (a -> Result a) -> a -> IO (Result a) forall b c a. (b -> c) -> (a -> b) -> a -> c .a -> Result a forall (m :: * -> *) a. Monad m => a -> m a return)(\IOException e ->ifIOException -> Bool isEOFErrorIOException e thendoBool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when(Conn a -> Bool forall a. Conn a -> Bool connCloseEOF Conn a conn )(IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $IO () -> (IOException -> IO ()) -> IO () forall a. IO a -> (IOException -> IO a) -> IO a catchIO (HandleStream a -> IO () forall bufType. HStream bufType => HandleStream bufType -> IO () closeQuick HandleStream a ref )(\IOException _->() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return())Result a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a return(a -> Result a forall (m :: * -> *) a. Monad m => a -> m a return(BufferOp a -> a forall a. BufferOp a -> a buf_empty (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )))elseResult a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a return(String -> Result a forall a. String -> Result a failMisc (IOException -> String forall a. Show a => a -> String showIOException e )))bufferPutBlock ::BufferOp a ->Handle->a ->IO(Result ())bufferPutBlock :: BufferOp a -> Handle -> a -> IO (Result ()) bufferPutBlock BufferOp a ops Handle h a b =IO (Result ()) -> (IOException -> IO (Result ())) -> IO (Result ()) forall a. IO a -> (IOException -> IO a) -> IO a catchIO (BufferOp a -> Handle -> a -> IO () forall a. BufferOp a -> Handle -> a -> IO () buf_hPut BufferOp a ops Handle h a b IO () -> IO () -> IO () forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >>Handle -> IO () hFlushHandle h IO () -> IO (Result ()) -> IO (Result ()) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >>Result () -> IO (Result ()) forall (m :: * -> *) a. Monad m => a -> m a return(() -> Result () forall (m :: * -> *) a. Monad m => a -> m a return()))(\IOException e ->Result () -> IO (Result ()) forall (m :: * -> *) a. Monad m => a -> m a return(String -> Result () forall a. String -> Result a failMisc (IOException -> String forall a. Show a => a -> String showIOException e )))bufferReadLine ::HStream a =>HandleStream a ->IO(Result a )bufferReadLine :: HandleStream a -> IO (Result a) bufferReadLine HandleStream a ref =HandleStream a -> (Conn a -> IO (Result a)) -> IO (Result a) forall a b. HandleStream a -> (Conn a -> IO (Result b)) -> IO (Result b) onNonClosedDo HandleStream a ref ((Conn a -> IO (Result a)) -> IO (Result a)) -> (Conn a -> IO (Result a)) -> IO (Result a) forall a b. (a -> b) -> a -> b $\Conn a conn ->docaseConn a -> Maybe a forall a. Conn a -> Maybe a connInput Conn a conn ofJusta c ->dolet(a a ,a b0 )=BufferOp a -> (Char -> Bool) -> a -> (a, a) forall a. BufferOp a -> (Char -> Bool) -> a -> (a, a) buf_span (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )(Char -> Char -> Bool forall a. Eq a => a -> a -> Bool /=Char '\n')a c let(a newl ,a b1 )=BufferOp a -> Int -> a -> (a, a) forall a. BufferOp a -> Int -> a -> (a, a) buf_splitAt (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )Int 1a b0 MVar (Conn a) -> (Conn a -> IO (Conn a)) -> IO () forall a. MVar a -> (a -> IO a) -> IO () modifyMVar_(HandleStream a -> MVar (Conn a) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream a ref )(\Conn a co ->Conn a -> IO (Conn a) forall (m :: * -> *) a. Monad m => a -> m a returnConn a co {connInput :: Maybe a connInput =a -> Maybe a forall a. a -> Maybe a Justa b1 })Result a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a return(a -> Result a forall (m :: * -> *) a. Monad m => a -> m a return(BufferOp a -> a -> a -> a forall a. BufferOp a -> a -> a -> a buf_append (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )a a a newl ))Maybe a _->IO (Result a) -> (IOException -> IO (Result a)) -> IO (Result a) forall a. IO a -> (IOException -> IO a) -> IO a catchIO (BufferOp a -> Handle -> IO a forall a. BufferOp a -> Handle -> IO a buf_hGetLine (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )(Conn a -> Handle forall a. Conn a -> Handle connHandle Conn a conn )IO a -> (a -> IO (Result a)) -> IO (Result a) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>=Result a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a return(Result a -> IO (Result a)) -> (a -> Result a) -> a -> IO (Result a) forall b c a. (b -> c) -> (a -> b) -> a -> c .a -> Result a forall (m :: * -> *) a. Monad m => a -> m a return(a -> Result a) -> (a -> a) -> a -> Result a forall b c a. (b -> c) -> (a -> b) -> a -> c .BufferOp a -> a -> a forall a. BufferOp a -> a -> a appendNL (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn ))(\IOException e ->ifIOException -> Bool isEOFErrorIOException e thendoBool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when(Conn a -> Bool forall a. Conn a -> Bool connCloseEOF Conn a conn )(IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $IO () -> (IOException -> IO ()) -> IO () forall a. IO a -> (IOException -> IO a) -> IO a catchIO (HandleStream a -> IO () forall bufType. HStream bufType => HandleStream bufType -> IO () closeQuick HandleStream a ref )(\IOException _->() -> IO () forall (m :: * -> *) a. Monad m => a -> m a return())Result a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a return(a -> Result a forall (m :: * -> *) a. Monad m => a -> m a return(BufferOp a -> a forall a. BufferOp a -> a buf_empty (Conn a -> BufferOp a forall a. Conn a -> BufferOp a connBuffer Conn a conn )))elseResult a -> IO (Result a) forall (m :: * -> *) a. Monad m => a -> m a return(String -> Result a forall a. String -> Result a failMisc (IOException -> String forall a. Show a => a -> String showIOException e )))where-- yes, this s**ks.. _may_ have to be addressed if perf-- suggests worthiness.appendNL :: BufferOp a -> a -> a appendNL BufferOp a ops a b =BufferOp a -> a -> Word8 -> a forall a. BufferOp a -> a -> Word8 -> a buf_snoc BufferOp a ops a b Word8 nl nl ::Word8nl :: Word8 nl =Int -> Word8 forall a b. (Integral a, Num b) => a -> b fromIntegral(Char -> Int forall a. Enum a => a -> Int fromEnumChar '\n')onNonClosedDo ::HandleStream a ->(Conn a ->IO(Result b ))->IO(Result b )onNonClosedDo :: HandleStream a -> (Conn a -> IO (Result b)) -> IO (Result b) onNonClosedDo HandleStream a h Conn a -> IO (Result b) act =doConn a x <-MVar (Conn a) -> IO (Conn a) forall a. MVar a -> IO a readMVar(HandleStream a -> MVar (Conn a) forall a. HandleStream a -> MVar (Conn a) getRef HandleStream a h )caseConn a x ofConnClosed {}->Result b -> IO (Result b) forall (m :: * -> *) a. Monad m => a -> m a return(ConnError -> Result b forall a. ConnError -> Result a failWith ConnError ErrorClosed )Conn a _->Conn a -> IO (Result b) act Conn a x