@@ -32,10 +32,16 @@ module Streamly.Internal.Network.Inet.TCP
32 , connectionsOnLocalHost
32 , connectionsOnLocalHost
34 -- * TCP clients
34 -- * TCP clients
35− -- | Socket based reads and writes.
35+ -- | IP Address based operations.
36− , withConnection
36+ , connect
38− -- ** Source
44+ -- *** Source
40 -- , readUtf8
46 -- , readUtf8
41 -- , readLines
47 -- , readLines
@@ -50,7 +56,7 @@ module Streamly.Internal.Network.Inet.TCP
50 -- , readArraysOf
56 -- , readArraysOf
51 -- , readArrays
57 -- , readArrays
53− -- ** Sink
59+ -- *** Sink
55 -- , writeUtf8
61 -- , writeUtf8
56 -- , writeUtf8ByLines
62 -- , writeUtf8ByLines
@@ -84,13 +90,13 @@ module Streamly.Internal.Network.Inet.TCP
87−import Control.Monad.Catch (MonadCatch)
93+import Control.Monad.Catch (MonadCatch, MonadMask, bracket)
88import Control.Monad.IO.Class (MonadIO(..))
94import Control.Monad.IO.Class (MonadIO(..))
89import Data.Word (Word8)
95import Data.Word (Word8)
90import Network.Socket
96import Network.Socket
91 (Socket, PortNumber, SocketOption(..), Family(..), SockAddr(..),
97 (Socket, PortNumber, SocketOption(..), Family(..), SockAddr(..),
92 SocketType(..), defaultProtocol, maxListenQueue, tupleToHostAddress,
98 SocketType(..), defaultProtocol, maxListenQueue, tupleToHostAddress,
93− socket, connect)
99+ socket)
94import Prelude hiding (read)
100import Prelude hiding (read)
96import Streamly (MonadAsync)
102import Streamly (MonadAsync)
@@ -110,7 +116,7 @@ import qualified Streamly.Network.Socket as SK
110import qualified Streamly.Internal.Network.Socket as ISK
116import qualified Streamly.Internal.Network.Socket as ISK
112-------------------------------------------------------------------------------
118-------------------------------------------------------------------------------
113−-- TCP Servers
119+-- Accept (unfolds)
114-------------------------------------------------------------------------------
120-------------------------------------------------------------------------------
116-- | Unfold a tuple @(ipAddr, port)@ into a stream of connected TCP sockets.
122-- | Unfold a tuple @(ipAddr, port)@ into a stream of connected TCP sockets.
@@ -158,7 +164,7 @@ acceptOnPortLocal :: MonadIO m => Unfold m PortNumber Socket
158acceptOnPortLocal = UF.supplyFirst acceptOnAddr (127,0,0,1)
164acceptOnPortLocal = UF.supplyFirst acceptOnAddr (127,0,0,1)
160-------------------------------------------------------------------------------
166-------------------------------------------------------------------------------
161−-- Listen
167+-- Accept (streams)
162-------------------------------------------------------------------------------
168-------------------------------------------------------------------------------
164-- | Like 'connections' but binds on the specified IPv4 address of the machine
170-- | Like 'connections' but binds on the specified IPv4 address of the machine
@@ -206,15 +212,50 @@ connectionsOnLocalHost = connectionsOnAddr (127,0,0,1)
206-- TCP Clients
212-- TCP Clients
207-------------------------------------------------------------------------------
213-------------------------------------------------------------------------------
215+-- | Connect to the specified IP address and port number.
218+connect :: (Word8, Word8, Word8, Word8) -> PortNumber -> IO Socket
219+connect addr port = do
220+ sock <- socket AF_INET Stream defaultProtocol
221+ Net.connect sock $ SockAddrInet port (Net.tupleToHostAddress addr)
224+-- | Connect to a remote host using IP address and port and run the supplied
225+-- action on the resulting socket. 'withServerAddrM' makes sure that the
226+-- socket is closed on normal termination or in case of an exception. If
227+-- closing the socket raises an exception, then this exception will be raised
228+-- by 'withServerAddrM'.
231+{-# INLINABLE withServerAddrM #-}
232+withServerAddrM :: (MonadMask m, MonadIO m)
233+ => (Word8, Word8, Word8, Word8) -> PortNumber -> (Socket -> m ()) -> m ()
234+withServerAddrM addr port =
235+ bracket (liftIO $ connect addr port) (liftIO . Net.close)
209-------------------------------------------------------------------------------
237-------------------------------------------------------------------------------
210−-- Connect
238+-- Connect (unfolds)
211-------------------------------------------------------------------------------
239-------------------------------------------------------------------------------
241+-- | Transform an 'Unfold' from a 'Socket' to an unfold from a remote IP
242+-- address and port. The resulting unfold opens a socket, uses it using the
243+-- supplied unfold and then makes sure that the socket is closed on normal
244+-- termination or in case of an exception. If closing the socket raises an
245+-- exception, then this exception will be raised by 'withServerAddr'.
248+{-# INLINABLE withServerAddr #-}
249+withServerAddr :: (MonadCatch m, MonadIO m)
250+ => Unfold m Socket a
213−openConnection :: (Word8, Word8, Word8, Word8) -> PortNumber -> IO Socket
251+ -> Unfold m ((Word8, Word8, Word8, Word8), PortNumber) a
214−openConnection addr port = do
252+withServerAddr =
215− sock <- socket AF_INET Stream defaultProtocol
253+ UF.bracket (\(addr, port) -> liftIO $ connect addr port)
216− connect sock $ SockAddrInet port (Net.tupleToHostAddress addr)
254+ (liftIO . Net.close)
256+-------------------------------------------------------------------------------
258+-------------------------------------------------------------------------------
219-- | @'withConnection' addr port act@ opens a connection to the specified IPv4
260-- | @'withConnection' addr port act@ opens a connection to the specified IPv4
220-- host address and port and passes the resulting socket handle to the
261-- host address and port and passes the resulting socket handle to the
@@ -228,7 +269,7 @@ openConnection addr port = do
228withConnection :: (IsStream t, MonadCatch m, MonadIO m)
269withConnection :: (IsStream t, MonadCatch m, MonadIO m)
229 => (Word8, Word8, Word8, Word8) -> PortNumber -> (Socket -> t m a) -> t m a
270 => (Word8, Word8, Word8, Word8) -> PortNumber -> (Socket -> t m a) -> t m a
230withConnection addr port =
271withConnection addr port =
231− S.bracket (liftIO $ openConnection addr port) (liftIO . Net.close)
272+ S.bracket (liftIO $ connect addr port) (liftIO . Net.close)
233-------------------------------------------------------------------------------
274-------------------------------------------------------------------------------
234-- Read Addr to Stream
275-- Read Addr to Stream
@@ -275,7 +316,7 @@ writeArrays
275writeArrays addr port = Fold step initial extract
316writeArrays addr port = Fold step initial extract
277 initial = do
318 initial = do
278− skt <- liftIO (openConnection addr port)
319+ skt <- liftIO (connect addr port)
279 FL.initialize (SK.writeArrays skt)
320 FL.initialize (SK.writeArrays skt)
280 step = FL.runStep
321 step = FL.runStep
281 extract (Fold _ initial1 extract1) = initial1 >>= extract1
322 extract (Fold _ initial1 extract1) = initial1 >>= extract1