packages feed

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 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" $