tcp-streams 0.2.2.0 → 0.2.3.0
raw patch · 6 files changed
+58/−33 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ System.IO.Streams.TCP: acceptWithBufferSize :: Socket -> Int -> IO (InputStream ByteString, OutputStream ByteString, Socket, SockAddr)
+ System.IO.Streams.TCP: close :: Socket -> IO ()
+ System.IO.Streams.TCP: socketToStreamsWithBufferSize :: Int -> Socket -> IO (InputStream ByteString, OutputStream ByteString)
Files
- ChangeLog.md +4/−0
- System/IO/Streams/OpenSSL.hs +4/−3
- System/IO/Streams/TCP.hs +34/−16
- System/IO/Streams/TLS.hs +5/−5
- tcp-streams.cabal +1/−1
- test/Main.hs +10/−8
ChangeLog.md view
@@ -1,5 +1,9 @@ # Revision history for tcp-simple +## 0.2.3.0++* Add `acceptWithBufferSize`, `socketToStreamsWithBufferSize`, fix recv exception handler.+ ## 0.2.2.0 * Clean and document exception behavior.
System/IO/Streams/OpenSSL.hs view
@@ -52,13 +52,14 @@ return (is, os) where- input = do+ input = ( do s <- SSL.read ssl bUFSIZ return $! if S.null s then Nothing else Just s- `E.onException` return Nothing+ ) `E.catch` (\(_::E.SomeException) -> return Nothing) output Nothing = return () output (Just s) = SSL.write ssl s+{-# INLINABLE sslToStreams #-} closeSSL :: SSL.SSL -> IO () closeSSL ssl = do@@ -132,7 +133,7 @@ eatException m = void m `E.catch` (\(_::E.SomeException) -> return ()) --- | accept a new connection from remote client, return a 'InputStream' / 'OutputStream'+-- | Accept a new connection from remote client, return a 'InputStream' / 'OutputStream' -- pair and remote 'N.SockAddr', you should call 'TCP.bindAndListen' first. -- -- this operation will throw 'SSL.SomeSSLException' on failure.
System/IO/Streams/TCP.hs view
@@ -4,10 +4,10 @@ -- with raw tcp. the default receive buffer size is 4096. sending is unbuffered, -- anything write into 'OutputStream' will be immediately send to underlying socket. ----- Reading 'InputStream' will block until message comming, for example--- `System.IO.Streams.ByteString.readExactly 1024` will block until 1024 bytes are available.+-- Reading 'InputStream' will block until GHC IO manager find data is ready,+-- 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'),+-- When socket is closed, the 'InputStream' will be closed too(further reading will return '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).@@ -23,6 +23,10 @@ -- * tcp server , bindAndListen , accept+ , acceptWithBufferSize+ -- * helpers+ , socketToStreamsWithBufferSize+ , N.close ) where import Control.Concurrent.MVar (withMVar)@@ -39,7 +43,7 @@ bUFSIZ :: Int bUFSIZ = 4096 --- | resolve a 'HostName'/'PortNumber' combination.+-- | Resolve a 'HostName'/'PortNumber' combination. -- -- This function throws an 'IOError' when resolve fail. --@@ -82,7 +86,7 @@ ) --- | connect to remote tcp server.+-- | Connect to remote tcp server. -- -- You may need to use 'E.bracket' pattern to enusre 'N.Socket' 's safety. --@@ -91,7 +95,7 @@ -> IO (InputStream ByteString, OutputStream ByteString, Socket) connect host port = connectWithBufferSize host port bUFSIZ --- | connect to remote tcp server with a receive buffer size.+-- | Connect to remote tcp server with adjustable receive buffer size. -- connectWithBufferSize :: HostName -- ^ hostname to connect to -> PortNumber -- ^ port number to connect to@@ -119,13 +123,12 @@ where go (is, os, sock) = action is os sock - cleanup (_, os, sock) = E.mask_ $ do- eatException $! Stream.write Nothing os- eatException $! N.close sock+ cleanup (_, os, sock) = E.mask_ $+ eatException $! Stream.write Nothing os >> N.close sock eatException m = void m `E.catch` (\(_::E.SomeException) -> return ()) --- | bind and listen on port with a limit on connection count.+-- | Bind and listen on port with a limit on connection count. -- bindAndListen :: PortNumber -> Int -> IO Socket bindAndListen port maxc = do@@ -143,17 +146,32 @@ return sock ) --- | accept a new connection from remote client, return a 'InputStream' / 'OutputStream' pair,+-- | 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 if there's no connection comming. -- accept :: Socket -> IO (InputStream ByteString, OutputStream ByteString, N.Socket, N.SockAddr)-accept sock = do+accept sock = acceptWithBufferSize sock bUFSIZ+++-- | accept a connection with adjustable receive buffer size.+--+acceptWithBufferSize :: Socket -> Int -> IO (InputStream ByteString, OutputStream ByteString, N.Socket, N.SockAddr)+acceptWithBufferSize sock bufsiz = do (sock', sockAddr) <- N.accept sock- (is, os) <- socketToStreamsWithBufferSize bUFSIZ sock'+ (is, os) <- socketToStreamsWithBufferSize bufsiz sock' return (is, os, sock', sockAddr) ++-- | Convert a 'Socket' into a streams pair, catch 'IOException's on receiving and close 'InputStream'.+-- 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).+--+-- During receiving, the status 'Control.Concurrent.MVar.MVar' is locked, so that a cleanup thread+-- can't affect receiving until finish.+-- socketToStreamsWithBufferSize :: Int -- ^ how large the receive buffer should be -> Socket -- ^ network socket@@ -162,15 +180,15 @@ is <- Stream.makeInputStream input os <- Stream.makeOutputStream output return (is, os)- where input = withMVar statusMVar $ \ status -> case status of- N.Connected -> do+ N.Connected -> ( do s <- NB.recv sock bufsiz return $! if B.null s then Nothing else Just s- `E.onException` return Nothing+ ) `E.catch` (\(_::E.IOException) -> return Nothing) _ -> return Nothing output Nothing = return () output (Just s) = unless (B.null s) (NB.sendAll sock s)+{-# INLINABLE socketToStreamsWithBufferSize #-}
System/IO/Streams/TLS.hs view
@@ -44,16 +44,16 @@ os <- Stream.makeOutputStream output return (is, os) where- input = do+ input = ( do s <- TLS.recvData ctx return $! if B.null s then Nothing else Just s- `E.onException` return Nothing+ ) `E.catch` (\(_::E.SomeException) -> return Nothing) output Nothing = return () output (Just s) = TLS.sendData ctx (fromStrict s)-+{-# INLINABLE tlsToStreams #-} --- | close a TLS 'Context' and its underlying socket.+-- | Close a TLS 'Context' and its underlying socket. -- closeTLS :: Context -> IO () closeTLS ctx = TLS.bye ctx >> TLS.contextClose ctx@@ -105,7 +105,7 @@ eatException m = void m `E.catch` (\(_::E.SomeException) -> return ()) --- | accept a new connection from remote client, return a 'InputStream' / 'OutputStream'+-- | Accept a new connection from remote client, return a 'InputStream' / 'OutputStream' -- pair and remote 'N.SockAddr', you should call 'TCP.bindAndListen' first. -- -- this operation will throw 'TLS.TLSException' on failure.
tcp-streams.cabal view
@@ -1,5 +1,5 @@ name: tcp-streams-version: 0.2.2.0+version: 0.2.3.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
test/Main.hs view
@@ -61,9 +61,8 @@ sock <- Raw.bindAndListen 8888 1024 putMVar mvar () (is, os, csock, _) <- Raw.accept sock- Stream.toList is >>= flip Stream.writeList os- os `Stream.connectTo` is- N.sClose csock+ is' <- Stream.atEndOfInput (N.close csock) is+ os `Stream.connectTo` is' N.sClose sock ------------------------------------------------------------------------------@@ -98,9 +97,10 @@ sp <- TLS.makeServerParams "./test/cert/server.crt" [] "./test/cert/server.key" sock <- Raw.bindAndListen 8889 1024 putMVar mvar ()- (is, os, _, _) <- TLS.accept sp sock- os `Stream.connectTo` is-+ (is, os, tls, _) <- TLS.accept sp sock+ is' <- Stream.atEndOfInput (Stream.write Nothing os >> TLS.closeTLS tls) is+ os `Stream.connectTo` is'+ N.sClose sock testHTTPS :: Test testHTTPS = testCase "network/socket" $@@ -150,8 +150,10 @@ sp <- SSL.makeServerSSLContext "./test/cert/server.crt" [] "./test/cert/server.key" sock <- Raw.bindAndListen 8890 1024 putMVar mvar ()- (is, os, _, _) <- SSL.accept sp sock- os `Stream.connectTo` is+ (is, os, ssl, _) <- SSL.accept sp sock+ is' <- Stream.atEndOfInput (Stream.write Nothing os >> SSL.closeSSL ssl) is+ os `Stream.connectTo` is'+ N.close sock testHTTPS' :: Test testHTTPS' = testCase "network/socket" $