pipes-network 0.1.0.1 → 0.1.1.0
raw patch · 7 files changed
+65/−278 lines, 7 filesdep +network-simplePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: network-simple
API changes (from Hackage documentation)
- Control.Proxy.TCP: bindSock :: HostPreference -> ServiceName -> IO (Socket, SockAddr)
- Control.Proxy.TCP: connectSock :: HostName -> ServiceName -> IO (Socket, SockAddr)
- Control.Proxy.TCP: data HostPreference
+ Control.Proxy.TCP: data HostPreference :: *
- Control.Proxy.TCP.Safe: data HostPreference
+ Control.Proxy.TCP.Safe: data HostPreference :: *
Files
- AUTHORS +0/−3
- PEOPLE +7/−0
- README.md +1/−1
- pipes-network.cabal +24/−22
- src/Control/Proxy/Network/Internal.hs +2/−39
- src/Control/Proxy/TCP.hs +20/−202
- src/Control/Proxy/TCP/Safe.hs +11/−11
− AUTHORS
@@ -1,3 +0,0 @@-Renzo Carbonara-Gabriel Gonzalez-Paolo Capriotti
+ PEOPLE view
@@ -0,0 +1,7 @@+The following people have participated in creating this library, either+by directly contributing code or by providing thoughtful input in+discussions about the library design.++Renzo Carbonara+Gabriel Gonzalez+Paolo Capriotti
README.md view
@@ -9,5 +9,5 @@ license**. Read the file named ``LICENSE`` found in this same directory for details. -See the ``AUTHORS`` file to learn about the people involved in this+See the ``PEOPLE`` file to learn about the people involved in this effort.
pipes-network.cabal view
@@ -1,19 +1,19 @@-name: pipes-network-version: 0.1.0.1-license: BSD3-license-file: LICENSE-copyright: Copyright (c) Renzo Carbonara 2012-2013, Paolo Capriotti 2012-2012.-author: Renzo Carbonara-maintainer: renzocarbonaraλgmail.com-stability: Experimental-tested-with: GHC == 7.4.1-homepage: https://github.com/k0001/pipes-network-bug-reports: https://github.com/k0001/pipes-network/issues-category: Control, Pipes, Network-build-type: Simple-synopsis: Use network sockets together with the pipes library.-cabal-version: >=1.8-extra-source-files: README.md AUTHORS+name: pipes-network+version: 0.1.1.0+license: BSD3+license-file: LICENSE+copyright: Copyright (c) Renzo Carbonara 2012-2013, Paolo Capriotti 2012-2012.+author: Renzo Carbonara+maintainer: renzocarbonaraλgmail.com+stability: Experimental+tested-with: GHC == 7.4.1+homepage: https://github.com/k0001/pipes-network+bug-reports: https://github.com/k0001/pipes-network/issues+category: Pipes, Network+build-type: Simple+synopsis: Use network sockets together with the pipes library.+cabal-version: >=1.8+extra-source-files: README.md PEOPLE description: Use network sockets together with the @pipes@ library. .@@ -34,18 +34,20 @@ library hs-source-dirs: src build-depends:- base (== 4.*),- bytestring (>= 0.9.2.1),+ base (==4.*),+ bytestring (>=0.9.2.1), network,- pipes (>=3.1 && <3.3),- pipes-safe (>=1.0),- transformers (>= 0.2 && < 0.4)+ network-simple (>=0.1 && <0.2),+ pipes (>=3.1 && <3.3),+ pipes-safe (>=1.0),+ transformers (>=0.2 && <0.4) exposed-modules:- Control.Proxy.Network.Internal Control.Proxy.TCP Control.Proxy.TCP.Sync Control.Proxy.TCP.Safe Control.Proxy.TCP.Safe.Sync+ other-modules:+ Control.Proxy.Network.Internal ghc-options: -Wall -fno-warn-unused-do-bind test-suite simple
src/Control/Proxy/Network/Internal.hs view
@@ -3,53 +3,16 @@ -- | This module doesn't belong to this namespace, but really, I don't -- know where it belongs. Suggestions welcome.---- Some code in this file was adapted from the @network-conduit@ library by--- Michael Snoyman. Copyright (c) 2011. See its licensing terms (BSD3) at:--- https://github.com/snoyberg/conduit/blob/master/network-conduit/LICENSE+--+-- There's a @data-timeout@ package, maybe we should depend on that. module Control.Proxy.Network.Internal (- HostPreference(..),- hpHostName, Timeout(..) ) where import qualified Control.Exception as E-import Data.String (IsString (fromString)) import Data.Typeable (Typeable)-import qualified Network.Socket as NS --- | Preferred host to bind.-data HostPreference- = HostAny -- ^Any available host.- | HostIPv4 -- ^Any available IPv4 host.- | HostIPv6 -- ^Any available IPv6 host.- | Host NS.HostName -- ^An explicit host name.- deriving (Eq, Ord, Show, Read)----- | The following special values are recognized:------ * @*@ means 'HostAny'------ * @*4@ means 'HostIPv4'------ * @*6@ means 'HostIPv6'------ * Any other string is 'Host'-instance IsString HostPreference where- fromString "*" = HostAny- fromString "*4" = HostIPv4- fromString "*6" = HostIPv6- fromString s = Host s----- | Extract the 'NS.HostName' from a 'Host' preference, or 'Nothing' otherwise.-hpHostName:: HostPreference -> Maybe NS.HostName-hpHostName (Host s) = Just s-hpHostName _ = Nothing---------------------------------------------------------------------------------- -- |Exception thrown when a timeout has elapsed. data Timeout
src/Control/Proxy/TCP.hs view
@@ -4,46 +4,43 @@ -- Instead, if want to safely acquire and release resources within the -- pipeline itself, then you should use the functions exported by -- "Control.Proxy.TCP.Safe".+--+-- This module re-exports many functions from "Network.Simple.TCP"+-- module in the @network-simple@ package. You might refer to that+-- module for more documentation. --- Some code in this file was adapted from the @network-conduit@ library by--- Michael Snoyman. Copyright (c) 2011. See its licensing terms (BSD3) at:--- https://github.com/snoyberg/conduit/blob/master/network-conduit/LICENSE module Control.Proxy.TCP ( -- * Server side -- $server-side- serve,- serveFork,+ S.serve+ , S.serveFork -- ** Listening- listen,+ , S.listen -- ** Accepting- accept,- acceptFork,+ , S.accept+ , S.acceptFork -- * Client side -- $client-side- connect,+ , S.connect -- * Socket streams -- $socket-streaming- socketReadS,- nsocketReadS,- socketWriteD,+ , socketReadS+ , nsocketReadS+ , socketWriteD -- ** Timeouts -- $socket-streaming-timeout- socketReadTimeoutS,- nsocketReadTimeoutS,- socketWriteTimeoutD,- -- * Low level support- bindSock,- connectSock,+ , socketReadTimeoutS+ , nsocketReadTimeoutS+ , socketWriteTimeoutD+ -- * Exports- HostPreference(..),- Timeout(..)+ , S.HostPreference(..)+ , Timeout(..) ) where -import Control.Concurrent (ThreadId, forkIO)-import qualified Control.Exception as E import Control.Monad import Control.Monad.Trans.Class import qualified Control.Proxy as P@@ -51,9 +48,9 @@ import Control.Proxy.Network.Internal import qualified Data.ByteString as B import Data.Monoid-import Data.List (partition) import qualified Network.Socket as NS import Network.Socket.ByteString (recv, sendAll)+import qualified Network.Simple.TCP as S import System.Timeout (timeout) --------------------------------------------------------------------------------@@ -71,21 +68,6 @@ -- > -- possibly with any of the socketReadS, nsocketReadS or socketWriteD -- > -- proxies explained below. --- | Connect to a TCP server and use the connection.------ The connection socket is closed when done or in case of exceptions.------ If you prefer to acquire and close the socket yourself, then use--- 'connectSock' and the 'NS.sClose' function from "Network.Socket" instead.-connect- :: NS.HostName -- ^Server hostname.- -> NS.ServiceName -- ^Server service port.- -> ((NS.Socket, NS.SockAddr) -> IO r)- -- ^Computation taking the communication socket- -- and the server address.- -> IO r-connect host port = E.bracket (connectSock host port) (NS.sClose . fst)- -------------------------------------------------------------------------------- -- $server-side@@ -109,99 +91,6 @@ -- example using a pretty general approach, you are encouraged to use simpler -- approaches such as 'serve' if those suit your needs. --- | Bind a TCP listening socket and use it.------ The listening socket is closed when done or in case of exceptions.------ If you prefer to acquire and close the socket yourself, then use--- 'bindSock' and the 'NS.listen' and 'NS.sClose' functions from--- "Network.Socket" instead.------ Note: 'N.maxListenQueue' is tipically 128, which is too small for high--- performance servers. So, we use the maximum between 'N.maxListenQueue' and--- 2048 as the default size of the listening queue.-listen- :: HostPreference -- ^Preferred host to bind.- -> NS.ServiceName -- ^Service port to bind.- -> ((NS.Socket, NS.SockAddr) -> IO r)- -- ^Computation taking the listening socket and- -- the address it's bound to.- -> IO r-listen hp port = E.bracket listen' (NS.sClose . fst)- where- listen' = do x@(bsock,_) <- bindSock hp port- NS.listen bsock $ max 2048 NS.maxListenQueue- return x---- | Start a TCP server that sequentially accepts and uses each incoming--- connection.------ Both the listening and connection sockets are closed when done or in case of--- exceptions.------ Note: You don't need to use 'listen' nor 'accept' if you use this function.-serve- :: HostPreference -- ^Preferred host to bind.- -> NS.ServiceName -- ^Service port to bind.- -> ((NS.Socket, NS.SockAddr) -> IO r)- -- ^Computation to run once an incoming- -- connection is accepted. Takes the connection socket- -- and remote end address.- -> IO r-serve hp port k = do- listen hp port $ \(lsock,_) -> do- forever $ accept lsock k---- | Start a TCP server that accepts incoming connections and uses them--- concurrently in different threads.------ The listening and connection sockets are closed when done or in case of--- exceptions.------ Note: You don't need to use 'listen' nor 'acceptFork' if you use this--- function.-serveFork- :: HostPreference -- ^Preferred host to bind.- -> NS.ServiceName -- ^Service port to bind.- -> ((NS.Socket, NS.SockAddr) -> IO ())- -- ^Computation to run in a different thread- -- once an incoming connection is accepted. Takes the- -- connection socket and remote end address.- -> IO ()-serveFork hp port k = do- listen hp port $ \(lsock,_) -> do- forever $ acceptFork lsock k---- | Accept a single incoming connection and use it.------ The connection socket is closed when done or in case of exceptions.-accept- :: NS.Socket -- ^Listening and bound socket.- -> ((NS.Socket, NS.SockAddr) -> IO b)- -- ^Computation to run once an incoming- -- connection is accepted. Takes the connection socket- -- and remote end address.- -> IO b-accept lsock k = do- conn@(csock,_) <- NS.accept lsock- E.finally (k conn) (NS.sClose csock)-{-# INLINABLE accept #-}---- | Accept a single incoming connection and use it in a different thread.------ The connection socket is closed when done or in case of exceptions.-acceptFork- :: NS.Socket -- ^Listening and bound socket.- -> ((NS.Socket, NS.SockAddr) -> IO ())- -- ^Computation to run in a different thread- -- once an incoming connection is accepted. Takes the- -- connection socket and remote end address.- -> IO ThreadId-acceptFork lsock f = do- client@(csock,_) <- NS.accept lsock- forkIO $ E.finally (f client) (NS.sClose csock)-{-# INLINABLE acceptFork #-}- -------------------------------------------------------------------------------- -- $socket-streaming@@ -312,74 +201,3 @@ ex = Timeout $ "recv: " <> show wait <> " microseconds." {-# INLINABLE socketWriteTimeoutD #-} ------------------------------------------------------------------------------------- | Obtain a 'NS.Socket' connected to the given host and TCP service port.------ The obtained 'NS.Socket' should be closed manually using 'NS.sClose' when--- it's not needed anymore, otherwise you risk having the socket open for much--- longer than needed.------ Prefer to use 'connect' if you will be using the socket within a limited--- scope and would like it to be closed immediately after its usage or in case--- of exceptions.-connectSock :: NS.HostName -> NS.ServiceName -> IO (NS.Socket, NS.SockAddr)-connectSock host port = do- (addr:_) <- NS.getAddrInfo (Just hints) (Just host) (Just port)- E.bracketOnError (newSocket addr) NS.sClose $ \sock -> do- let sockAddr = NS.addrAddress addr- NS.connect sock sockAddr- return (sock, sockAddr)- where- hints = NS.defaultHints { NS.addrFlags = [NS.AI_ADDRCONFIG]- , NS.addrSocketType = NS.Stream }---- | Obtain a 'NS.Socket' bound to the given host name and TCP service port.------ The obtained 'NS.Socket' should be closed manually using 'NS.sClose' when--- it's not needed anymore.------ Prefer to use 'listen' if you will be listening on this socket and using it--- within a limited scope, and would like it to be closed immediately after its--- usage or in case of exceptions.-bindSock :: HostPreference -> NS.ServiceName -> IO (NS.Socket, NS.SockAddr)-bindSock hp port = do- addrs <- NS.getAddrInfo (Just hints) (hpHostName hp) (Just port)- let addrs' = case hp of- HostIPv4 -> prioritize isIPv4addr addrs- HostIPv6 -> prioritize isIPv6addr addrs- _ -> addrs- tryAddrs addrs'- where- hints = NS.defaultHints { NS.addrFlags = [NS.AI_PASSIVE]- , NS.addrSocketType = NS.Stream }-- tryAddrs [] = error "bindSock: no addresses available"- tryAddrs [x] = useAddr x- tryAddrs (x:xs) = E.catch (useAddr x)- (\e -> let _ = e :: E.IOException in tryAddrs xs)-- useAddr addr = E.bracketOnError (newSocket addr) NS.sClose $ \sock -> do- let sockAddr = NS.addrAddress addr- NS.setSocketOption sock NS.NoDelay 1- NS.setSocketOption sock NS.ReuseAddr 1- NS.bindSocket sock sockAddr- return (sock, sockAddr)-------------------------------------------------------------------------------------- Misc--newSocket :: NS.AddrInfo -> IO NS.Socket-newSocket addr = NS.socket (NS.addrFamily addr)- (NS.addrSocketType addr)- (NS.addrProtocol addr)--isIPv4addr, isIPv6addr :: NS.AddrInfo -> Bool-isIPv4addr x = NS.addrFamily x == NS.AF_INET-isIPv6addr x = NS.addrFamily x == NS.AF_INET6---- | Move the elements that match the predicate closer to the head of the list.--- Preserve relative order.-prioritize :: (a -> Bool) -> [a] -> [a]-prioritize p = uncurry (++) . partition p
src/Control/Proxy/TCP/Safe.hs view
@@ -39,7 +39,7 @@ socketWriteD, -- * Exports- HostPreference(..),+ S.HostPreference(..), Timeout(..) ) where @@ -48,12 +48,12 @@ import Control.Monad import qualified Control.Proxy as P import Control.Proxy.Network.Internal-import qualified Control.Proxy.TCP as T import qualified Control.Proxy.Safe as P import qualified Data.ByteString as B import Data.Monoid import qualified Network.Socket as NS import Network.Socket.ByteString (sendAll, recv)+import qualified Network.Simple.TCP as S import System.Timeout (timeout) --------------------------------------------------------------------------------@@ -79,7 +79,7 @@ -- The connection socket is closed when done or in case of exceptions. -- -- If you prefer to acquire close the socket yourself, then use--- 'T.connectSock' and the 'NS.sClose' from "Network.Socket" instead.+-- 'S.connectSock' and the 'NS.sClose' from "Network.Socket" instead. connect :: (P.Proxy p, Monad m) => (forall x. P.SafeIO x -> m x) -- ^Monad morphism.@@ -91,7 +91,7 @@ -- address. -> P.ExceptionP p a' a b' b m r connect morph host port =- P.bracket morph (T.connectSock host port) (NS.sClose . fst)+ P.bracket morph (S.connectSock host port) (NS.sClose . fst) -------------------------------------------------------------------------------- @@ -180,7 +180,7 @@ -- The listening socket is closed when done or in case of exceptions. -- -- If you prefer to acquire and close the socket yourself, then use--- 'T.bindSock' and the 'NS.listen' and 'NS.sClose' functions from+-- 'S.bindSock' and the 'NS.listen' and 'NS.sClose' functions from -- "Network.Socket" instead. -- -- Note: 'N.maxListenQueue' is tipically 128, which is too small for high@@ -189,7 +189,7 @@ listen :: (P.Proxy p, Monad m) => (forall x. P.SafeIO x -> m x) -- ^Monad morphism.- -> HostPreference -- ^Preferred host to bind.+ -> S.HostPreference -- ^Preferred host to bind. -> NS.ServiceName -- ^Service port to bind. -> ((NS.Socket, NS.SockAddr) -> P.ExceptionP p a' a b' b m r) -- ^Computation taking the listening@@ -197,7 +197,7 @@ -> P.ExceptionP p a' a b' b m r listen morph hp port = P.bracket morph listen' (NS.sClose . fst) where- listen' = do x@(bsock,_) <- T.bindSock hp port+ listen' = do x@(bsock,_) <- S.bindSock hp port NS.listen bsock $ max 2048 NS.maxListenQueue return x @@ -211,7 +211,7 @@ serve :: (P.Proxy p, Monad m) => (forall x. P.SafeIO x -> m x) -- ^Monad morphism.- -> HostPreference -- ^Preferred host to bind.+ -> S.HostPreference -- ^Preferred host to bind. -> NS.ServiceName -- ^Service port to bind. -> ((NS.Socket, NS.SockAddr) -> P.ExceptionP p a' a b' b m r) -- ^Computation to run once an incoming@@ -233,7 +233,7 @@ serveFork :: (P.Proxy p, Monad m) => (forall x. P.SafeIO x -> m x) -- ^Monad morphism.- -> HostPreference -- ^Preferred host to bind.+ -> S.HostPreference -- ^Preferred host to bind. -> NS.ServiceName -- ^Service port to bind. -> ((NS.Socket, NS.SockAddr) -> IO ()) -- ^Computation to run in a different thread@@ -311,7 +311,7 @@ :: P.Proxy p => Maybe Int -- ^Optional timeout in microseconds (1/10^6 seconds). -> Int -- ^Maximum number of bytes to receive at once.- -> HostPreference -- ^Preferred host to bind.+ -> S.HostPreference -- ^Preferred host to bind. -> NS.ServiceName -- ^Service port to bind. -> () -> P.Producer (P.ExceptionP p) B.ByteString P.SafeIO () serveReadS mwait nbytes hp port () = do@@ -340,7 +340,7 @@ serveWriteD :: P.Proxy p => Maybe Int -- ^Optional timeout in microseconds (1/10^6 seconds).- -> HostPreference -- ^Preferred host to bind.+ -> S.HostPreference -- ^Preferred host to bind. -> NS.ServiceName -- ^Service port to bind. -> x -> (P.ExceptionP p) x B.ByteString x B.ByteString P.SafeIO () serveWriteD mwait hp port x = do