tcp-streams 0.2.1.0 → 0.2.2.0
raw patch · 5 files changed
+58/−31 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- System.IO.Streams.OpenSSL: CertificateVerifyFail :: CertificateVerifyFail
- System.IO.Streams.OpenSSL: data CertificateVerifyFail
- System.IO.Streams.OpenSSL: instance GHC.Classes.Eq System.IO.Streams.OpenSSL.CertificateVerifyFail
- System.IO.Streams.OpenSSL: instance GHC.Exception.Exception System.IO.Streams.OpenSSL.CertificateVerifyFail
- System.IO.Streams.OpenSSL: instance GHC.Show.Show System.IO.Streams.OpenSSL.CertificateVerifyFail
Files
- ChangeLog.md +4/−0
- System/IO/Streams/OpenSSL.hs +11/−14
- System/IO/Streams/TCP.hs +39/−15
- System/IO/Streams/TLS.hs +3/−1
- tcp-streams.cabal +1/−1
ChangeLog.md view
@@ -1,5 +1,9 @@ # Revision history for tcp-simple +## 0.2.2.0++* Clean and document exception behavior.+ ## 0.2.1.0 * Fix broken document.
System/IO/Streams/OpenSSL.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE DeriveDataTypeable #-} -- | This module provides convenience functions for interfacing @io-streams@ -- with @HsOpenSSL@. @ssl/SSL@ here stand for @HsOpenSSL@ library, not the@@ -7,7 +6,8 @@ -- sending is unbuffered, anything write into 'OutputStream' will be immediately -- send to underlying socket. ----- You should handle 'IOError' when you read/write these streams for safety.+-- The same exceptions rule which applied to TCP apply here, with addtional+-- 'SSL.SomeSSLException` to be watched out. -- -- Be sure to use 'withOpenSSL' wrap your operation before using any functions here. -- otherwise a segmentation fault will happen.@@ -22,11 +22,10 @@ , withOpenSSL , sslToStreams , closeSSL- , CertificateVerifyFail(..) ) where import qualified Control.Exception as E-import Control.Monad (void, unless)+import Control.Monad (unless, void) import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as S import Network.Socket (HostName, PortNumber, Socket)@@ -38,7 +37,6 @@ import System.IO.Streams (InputStream, OutputStream) import qualified System.IO.Streams as Streams import qualified System.IO.Streams.TCP as TCP-import Data.Typeable (Typeable) bUFSIZ :: Int bUFSIZ = 32752@@ -57,6 +55,7 @@ input = do s <- SSL.read ssl bUFSIZ return $! if S.null s then Nothing else Just s+ `E.onException` return Nothing output Nothing = return () output (Just s) = SSL.write ssl s@@ -70,8 +69,7 @@ -- @('HostName', 'PortNumber')@ combination. -- -- this function will try to verify server's identity,--- a 'CertificateVerifyFail' will be thrown if fail.--- it may throw 'SSL.SomeSSLException' too.+-- a 'SSL.ProtocolError' will be thrown if fail. -- connect :: SSLContext -- ^ SSL context. See the @HsOpenSSL@ -- documentation for information on creating@@ -92,16 +90,17 @@ verified = case subname of Just subname' -> maybe False (== subname') cnname Nothing -> maybe False (matchDomain host) cnname- unless (trusted && verified) (E.throwIO CertificateVerifyFail)+ unless (trusted && verified) (E.throwIO $ SSL.ProtocolError "fail to verify certificate") (is, os) <- sslToStreams ssl return (is, os, ssl) where matchDomain :: String -> String -> Bool matchDomain n1 n2 =- let n1' = (take 2 . reverse) (splitDot n1)- n2' = (take 2 . reverse) (splitDot n2)- in n1' == n2'+ let n1' = reverse (splitDot n1)+ n2' = reverse (splitDot n2)+ cmp src target = src == "*" || src == target+ in and (zipWith cmp n1' n2') splitDot :: String -> [String] splitDot "" = [""] splitDot x =@@ -146,9 +145,7 @@ E.bracketOnError (SSL.connection ctx sock') closeSSL $ \ ssl -> do SSL.accept ssl trusted <- SSL.getVerifyResult ssl- unless trusted (E.throwIO CertificateVerifyFail)+ unless trusted (E.throwIO $ SSL.ProtocolError "fail to verify certificate") (is, os) <- sslToStreams ssl return (is, os, ssl, sockAddr) -data CertificateVerifyFail = CertificateVerifyFail deriving (Show, Eq, Typeable)-instance E.Exception CertificateVerifyFail
System/IO/Streams/TCP.hs view
@@ -4,8 +4,15 @@ -- with raw tcp. the default receive buffer size is 4096. sending is unbuffered, -- anything write into 'OutputStream' will be immediately send to underlying socket. ----- You should handle 'IOError' when you read/write these streams for safety.--- Note, `TCP_NODELAY` are enabled by default. you can use 'N.setSocketOption' to adjust.+-- Reading 'InputStream' will block until message comming, for example+-- `System.IO.Streams.ByteString.readExactly 1024` will block until 1024 bytes are available.+--+-- When socket is closed, the 'InputStream' will be closed too(further reading 'Nothing'),+-- no exception will be thrown. You still should handle 'IOError' when you write to 'OutputStream' for safety,+-- but no exception doesn't essentially mean a successful write, especially under bad network+-- environment(broken wire for example).+--+-- `TCP_NODELAY` are enabled by default. you can use 'N.setSocketOption' to adjust. module System.IO.Streams.TCP ( -- * tcp client@@ -18,22 +25,23 @@ , accept ) where +import Control.Concurrent.MVar (withMVar) import qualified Control.Exception as E-import Control.Monad (void)-import Data.ByteString.Char8 (ByteString)-import Network.Socket (HostName, PortNumber, Socket)+import Control.Monad (unless, void)+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import Network.Socket (HostName, PortNumber, Socket (..)) import qualified Network.Socket as N+import qualified Network.Socket.ByteString as NB import System.IO.Streams (InputStream, OutputStream) import qualified System.IO.Streams as Stream-import System.IO.Streams.Network (socketToStreamsWithBufferSize) - bUFSIZ :: Int bUFSIZ = 4096 -- | resolve a 'HostName'/'PortNumber' combination. ----- This function throws an IO exception when resolve fail.+-- This function throws an 'IOError' when resolve fail. -- resolveAddrInfo :: HostName -> PortNumber -> IO (N.Family, N.SocketType, N.ProtocolNumber, N.SockAddr) resolveAddrInfo host port = do@@ -74,7 +82,6 @@ ) - -- | connect to remote tcp server. -- -- You may need to use 'E.bracket' pattern to enusre 'N.Socket' 's safety.@@ -82,11 +89,7 @@ connect :: HostName -- ^ hostname to connect to -> PortNumber -- ^ port number to connect to -> IO (InputStream ByteString, OutputStream ByteString, Socket)-connect host port = do- sock <- connectSocket host port- (is, os) <- socketToStreamsWithBufferSize bUFSIZ sock- return (is, os, sock)-+connect host port = connectWithBufferSize host port bUFSIZ -- | connect to remote tcp server with a receive buffer size. --@@ -143,10 +146,31 @@ -- | accept a new connection from remote client, return a 'InputStream' / 'OutputStream' pair, -- a new underlying 'Socket', and remote 'N.SockAddr',you should call 'bindAndListen' first. ----- This function will block current thread if there's no connection comming.+-- This function will block if there's no connection comming. -- accept :: Socket -> IO (InputStream ByteString, OutputStream ByteString, N.Socket, N.SockAddr) accept sock = do (sock', sockAddr) <- N.accept sock (is, os) <- socketToStreamsWithBufferSize bUFSIZ sock' return (is, os, sock', sockAddr)++socketToStreamsWithBufferSize+ :: Int -- ^ how large the receive buffer should be+ -> Socket -- ^ network socket+ -> IO (InputStream ByteString, OutputStream ByteString)+socketToStreamsWithBufferSize bufsiz sock@(MkSocket _ _ _ _ statusMVar) = do+ is <- Stream.makeInputStream input+ os <- Stream.makeOutputStream output+ return (is, os)++ where+ input = withMVar statusMVar $ \ status ->+ case status of+ N.Connected -> do+ s <- NB.recv sock bufsiz+ return $! if B.null s then Nothing else Just s+ `E.onException` return Nothing+ _ -> return Nothing++ output Nothing = return ()+ output (Just s) = unless (B.null s) (NB.sendAll sock s)
System/IO/Streams/TLS.hs view
@@ -5,7 +5,8 @@ -- sending is unbuffered, anything write into 'OutputStream' will be -- immediately send to underlying socket. ----- You should handle 'IOError' when you read/write these streams for safety.+-- The same exceptions rule which applied to TCP apply here, with addtional+-- 'TLS.TLSException' to be watched out. -- module System.IO.Streams.TLS ( -- * client@@ -46,6 +47,7 @@ input = do s <- TLS.recvData ctx return $! if B.null s then Nothing else Just s+ `E.onException` return Nothing output Nothing = return () output (Just s) = TLS.sendData ctx (fromStrict s)
tcp-streams.cabal view
@@ -1,5 +1,5 @@ name: tcp-streams-version: 0.2.1.0+version: 0.2.2.0 synopsis: One stop solution for tcp client and server with tls support. description: One stop solution for tcp client and server with tls support. license: BSD3