splice 0.1 → 0.2
raw patch · 2 files changed
+115/−31 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Network.Socket.Splice: loopSplice :: Length -> Socket -> Socket -> IO ()
- Network.Socket.Splice: type Length = Word32
+ Network.Socket.Splice: sPLICE_F_MORE :: Word
+ Network.Socket.Splice: sPLICE_F_MOVE :: Word
+ Network.Socket.Splice: sPLICE_F_NONBLOCK :: Word
+ Network.Socket.Splice: splice :: ChunkSize -> Socket -> Socket -> IO ()
+ Network.Socket.Splice: try_ :: IO () -> IO ()
+ Network.Socket.Splice: type ChunkSize = Word32
Files
- splice.cabal +8/−3
- src/Network/Socket/Splice.hsc +107/−28
splice.cabal view
@@ -1,5 +1,5 @@ name: splice-version: 0.1+version: 0.2 stability: stable on Linux, experimental on other operating systems synopsis: Socket to Socket Data Splicing description: A library that implements efficient socket to socket@@ -15,8 +15,13 @@ lots of tiny allocations as would otherwise be caused by recv and sendAll functions from Network.Socket.ByteString. .- This work has been funded by Corsis Research and is used- in PortFusion: <http://portfusion.sf.net>+ This work is funded by Corsis Research and used in:+ .+ PortFusion ]-[ayabusa – German+ research project for building the simplest+ high-performance distributed reverse / forward proxy.+ .+ <https://sourceforge.net/p/portfusion/wiki/RoadMap/> license: BSD3 license-file: LICENSE author: Cetin Sert <fusion@corsis.eu>
src/Network/Socket/Splice.hsc view
@@ -1,11 +1,24 @@--- |+{- |+ This library implements efficient socket to socket+ data transfer loops for proxy servers.+ + On Linux, it uses the zero-copy splice() system call:+ <http://kerneltrap.org/node/6505>.++ On all other operating systems, it currently falls back+ to a portable Haskell implementation that allocates a+ constant-sized memory buffer before it enters an inner+ loop which then uses hGetBufSome and hPutBuf; this avoids+ lots of tiny allocations as would otherwise be caused by+ recv and sendAll functions from Network.Socket.ByteString.+-}+-- -- Module : Network.Socket.Splice -- Copyright : (c) Cetin Sert 2012 -- License : BSD-style--- -- Maintainer : fusion@corsis.eu -- Stability : stable--- Portability : GHC-only+-- Portability : GHC-only, works on all OSes #ifdef LINUX_SPLICE #include <fcntl.h>@@ -14,12 +27,40 @@ #endif module Network.Socket.Splice (- Length++ -- * Cross-platform API for Socket to Socket Data Transfer Loops+ {- | 'splice' is the cross-platform API for continous, uni-directional+ data transfer between two network sockets.++ It is an /infinite loop/ that is intended to be used with+ 'Control.Concurrent.forkIO':++ > void . forkIO . try_ $ splice 1024 sourceSocket targetSocket+ > void . forkIO . try_ $ splice 1024 targetSocket sourceSocket+ -}++ splice+ , ChunkSize , zeroCopy- , loopSplice++ -- * Combinators for Exception Handling+ , try_+++ -- * Linux splice() Components+ {- | These are available only on Linux and+ will be moved to a different namespace+ in later releases. Their names will stay+ the same.+ -}+ #ifdef LINUX_SPLICE , c_splice+ , sPLICE_F_MOVE+ , sPLICE_F_MORE+ , sPLICE_F_NONBLOCK #endif+ ) where import Data.Word@@ -45,9 +86,9 @@ #endif --- | Indicates whether 'loopSplice' uses zero copy system calls+-- | Indicates whether 'splice' uses zero-copy system calls -- or the portable user mode Haskell substitue implementation.-zeroCopy :: Bool -- ^ True: system calls; otherwise: portable.+zeroCopy :: Bool -- ^ True: uses zero-copy system calls; otherwise: portable. zeroCopy = #ifdef LINUX_SPLICE True@@ -58,31 +99,32 @@ -------------------------------------------------------------------------------- --type Length =+-- | The numeric type used to recommend chunk sizes for moving+-- data between sockets used by both the Linux 'splice' and+-- the portable implementation of 'splice'.+type ChunkSize = #ifdef LINUX_SPLICE (#type size_t) #else Int #endif -try_ :: IO () -> IO ()-try_ a = (try a :: IO (Either SomeException ())) >> return () ---- | The 'loopSplice' function pipes data from--- one socket to another in an infinite loop.+-- | Pipes data from one socket to another in an+-- **infinite loop**.+-- -- On Linux this happens in kernel space with--- zero copying, between kernel and user space.+-- zero copying between kernel and user spaces.+-- -- On other operating systems, a portable -- implementation utilizes a user space buffer -- and works on handles instead of file descriptors.-loopSplice- :: Length -- ^ Splice length- -> Socket -- ^ Source socket- -> Socket -- ^ Target socket- -> IO ()-loopSplice len sIn sOut = do+splice+ :: ChunkSize -- ^ Chunk size.+ -> Socket -- ^ Source socket.+ -> Socket -- ^ Target socket.+ -> IO () -- ^ Infinite loop.+splice len sIn sOut = do let throwRecv0 = error "Network.Socket.Splice.splice ended" @@ -139,6 +181,15 @@ #endif +-- | Similar to 'Control.Exception.Base.try' but used when an+-- obvious exception is expected whose type can be safely+-- ignored.+try_+ :: IO () -- ^ The action to run which can throw any exception.+ -> IO () -- ^ The new action where exceptions are silenced.+try_ a = (try a :: IO (Either SomeException ())) >> return ()++ -------------------------------------------------------------------------------- @@ -155,19 +206,47 @@ -- unsigned int flags -- ); +-- | Moves data between two file descriptors without+-- copying between kernel address space and user +-- address space. It transfers up to 'len' bytes of+-- data from the file descriptor 'fd_in' to the file+-- file descriptor 'fd_out', where one of the+-- descriptors must refer to a pipe.+--+-- 'c_splice' is NOT a loop and needs to called repeatedly.+-- For an example, see the source code of 'splice'. foreign import ccall "splice" c_splice- :: Fd- -> Ptr (#type loff_t)- -> Fd- -> Ptr (#type loff_t)- -> (#type size_t)- -> Word- -> IO (#type ssize_t)+ :: Fd -- ^ fd_in+ -> Ptr (#type loff_t) -- ^ off_in+ -> Fd -- ^ fd_out+ -> Ptr (#type loff_t) -- ^ off_out+ -> (#type size_t) -- ^ len+ -> Word -- ^ flags+ -> IO (#type ssize_t) -- ^ number of bytes moved or -1 on error ++-- | Attempt to move pages instead of copying. This is+-- only a hint to the kernel: pages may stil be copied+-- if the kernel cannot move the pages from the pipe,+-- or if the pipe buffers don't refer to full pages. sPLICE_F_MOVE :: Word sPLICE_F_MOVE = (#const "SPLICE_F_MOVE") ++-- | More data will be coming in a subsequent splice.+-- This is a helpful hint when 'fd_out' refers to a+-- socket. sPLICE_F_MORE :: Word sPLICE_F_MORE = (#const "SPLICE_F_MORE")+++-- | Do not block on I/O. This makes the splice pipe+-- operations nonblocking, but splice() may nevertheless+-- block because the file descriptors that are spliced+-- to/from may block (unless they have the O_NONBLOCK flag+-- set).+sPLICE_F_NONBLOCK :: Word+sPLICE_F_NONBLOCK = (#const "SPLICE_F_NONBLOCK")+ #endif