splice 0.6.0.2 → 0.6.1
raw patch · 5 files changed
+452/−443 lines, 5 filesdep ~basedep ~network
Dependency ranges changed: base, network
Files
- LICENSE +31/−31
- splice.cabal +65/−65
- src/Network/Socket/Splice.hs +29/−29
- src/Network/Socket/Splice/Internal.hsc +250/−242
- src/System/IO/Splice/Linux.hsc +77/−76
LICENSE view
@@ -1,31 +1,31 @@-Copyright (c) 2012, Cetin Sert--All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are-met:-- * Redistributions of source code must retain the above copyright- notice, this list of conditions and the following disclaimer.-- * Redistributions in binary form must reproduce the above- copyright notice, this list of conditions and the following- disclaimer in the documentation and/or other materials provided- with the distribution.-- * The names of contributors may not be used to endorse or promote- products derived from this software without specific prior- written permission. --THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+Copyright (c) 2012, Cetin Sert + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of contributors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
splice.cabal view
@@ -1,65 +1,65 @@-name: splice-version: 0.6.0.2-stability: stable on all operating systems-synopsis: Cross-platform Socket to Socket Data Splicing-description: A library that implements most efficient socket to socket- data transfer loops for proxy servers on all operating systems.- .- On GNU/Linux, it uses the zero-copy @splice()@ system- call (<http://kerneltrap.org/node/6505>) and exports it as- @c_splice@ in @System.IO.Splice.Linux@.- .- On other operating systems, it uses a portable Haskell- implementation.- .- [Legal]- This work is undertaken by Corsis Research for the development of- PortFusion \]-\[ayabusa (はやぶさ) (Hayabusa) - (<https://fusion.corsis.eu>) – German-Japanese joint research- project for building the simplest and most concise- high-performance distributed reverse / forward proxy application- possible on commodity hardware and operating systems.-copyright: Copyright © 2012 Cetin Sert-license: BSD3-license-file: LICENSE-author: Cetin Sert <fusion@corsis.eu>-maintainer: Cetin Sert <fusion@corsis.eu>-homepage: http://corsis.github.com/splice/-bug-reports: http://github.com/corsis/splice/issues-category: System, Network-build-type: Simple-cabal-version: >=1.6---source-repository head- type: git- location: git://github.com/corsis/splice.git---flag portable- description: force portable 'splice' implementation on GNU\/Linux- default : False---flag llvm- description: compile via LLVM- default : False---library- hs-source-dirs: src- exposed-modules: Network.Socket.Splice- other-modules: Network.Socket.Splice.Internal- build-depends: base >= 4 && <= 6,- network >= 2 && <= 4-- if os(linux) && !flag(portable)- exposed-modules: System.IO.Splice.Linux- build-depends: unix >= 2 && <= 4- cpp-options: -DLINUX_SPLICE--- ghc-options: -Wall -O2 -O3-- if flag(llvm)- ghc-options: -fllvm -optlo-O3 -msse4.2+name: splice +version: 0.6.1 +stability: stable on all operating systems +synopsis: Cross-platform Socket to Socket Data Splicing +description: A library that implements most efficient socket to socket + data transfer loops for proxy servers on all operating systems. + . + On GNU/Linux, it exports the zero-copy system call @c_splice()@ + (<http://kerneltrap.org/node/6505>) in @System.IO.Splice.Linux@. + . + On other operating systems, it only exports a portable Haskell + implementation. + . + A unified sockets API for all operating systems is available in + @Network.Socket.Splice@. + . + [Version Scheme] + Major-@/R/@-ewrite . New-@/F/@-unctionality . @/I/@-mprovementAndBugFixes . @/P/@-ackagingOnly + . + * @PackagingOnly@ changes are made for quality assurance reasons. + +copyright: Copyright © 2012 Cetin Sert +license: BSD3 +license-file: LICENSE +author: Cetin Sert <fusion@corsis.eu>, Corsis Research +maintainer: Cetin Sert <fusion@corsis.eu>, Corsis Research +homepage: http://corsis.github.com/splice/ +bug-reports: http://github.com/corsis/splice/issues +category: System, Network +build-type: Simple +cabal-version: >= 1.6 + + +source-repository head + type: git + location: git://github.com/corsis/splice.git + + +flag portable + description: force portable 'splice' implementation on GNU\/Linux + default : True + + +flag llvm + description: compile via LLVM + default : False + + +library + hs-source-dirs: src + exposed-modules: Network.Socket.Splice + other-modules: Network.Socket.Splice.Internal + build-depends: base >= 4 && <= 5, + network -any + + if os(linux) && !flag(portable) + exposed-modules: System.IO.Splice.Linux + build-depends: unix >= 2 && <= 4 + cpp-options: -DLINUX_SPLICE + + + ghc-options: -Wall -O2 + + if flag(llvm) + ghc-options: -fllvm -optlo-O3
src/Network/Socket/Splice.hs view
@@ -1,29 +1,29 @@-{- |- This library implements most efficient socket to socket data transfer loops- for proxy servers on each operating system.- - On GNU\/Linux, it uses and exposes 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 – which allocates a single memory buffer in user address space,- then enters an inner loop that uses 'System.IO.hGetBufSome' and- 'System.IO.hPutBuf'. This avoids lots of tiny allocations as would otherwise- be caused by 'Network.Socket.ByteString.recv' and- 'Network.Socket.ByteString.sendAll' from the @bytestring@ package.--}--- --- Module : Network.Socket.Splice--- Copyright : (c) Cetin Sert 2012--- License : BSD3--- Maintainer : fusion@corsis.eu--- Stability : stable--- Portability : works on all operating systems--module Network.Socket.Splice (-- module Network.Socket.Splice.Internal-- ) where--import Network.Socket.Splice.Internal+{- | + This library implements most efficient socket to socket data transfer loops + for proxy servers on each operating system. + + On GNU\/Linux, it uses and exposes 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 – which allocates a single memory buffer in user address space, + then enters an inner loop that uses 'System.IO.hGetBufSome' and + 'System.IO.hPutBuf'. This avoids lots of tiny allocations as would otherwise + be caused by 'Network.Socket.ByteString.recv' and + 'Network.Socket.ByteString.sendAll' from the @bytestring@ package. +-} +-- +-- Module : Network.Socket.Splice +-- Copyright : (c) Cetin Sert 2012 +-- License : BSD3 +-- Maintainer : fusion@corsis.eu +-- Stability : stable +-- Portability : works on all operating systems + +module Network.Socket.Splice ( + + module Network.Socket.Splice.Internal + + ) where + +import Network.Socket.Splice.Internal
src/Network/Socket/Splice/Internal.hsc view
@@ -1,243 +1,251 @@--- | Implementation.------ Module : Network.Socket.Splice.Internal--- Copyright : (c) Cetin Sert 2012--- License : BSD3--- Maintainer : fusion@corsis.eu--- Stability : stable--- Portability : works on all operating systems---#ifdef LINUX_SPLICE-#include <fcntl.h>-#endif-{-# LANGUAGE CPP #-}-{-# LANGUAGE ForeignFunctionInterface #-}---module Network.Socket.Splice.Internal (-- -- * 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.-- 'splice' and its implementation primitives 'hSplice' and 'fdSplice' are- /infinite/ loops that are intended to be used with- 'Control.Concurrent.forkIO' and exception handlers. 'splice' is a- terminal operation; it cannot be interleaved by other IO operations on- its sockets or handles.-- [Initiate bi-directional continuous data transfer between two sockets:]- - > void . forkIO . tryWith handler $ splice 1024 (sourceSocket, _) (targetSocket, _)- > void . forkIO . tryWith handler $ splice 1024 (targetSocket, _) (sourceSocket, _)-- where @handler@ is an IO operation that would do the necessary clean up –- such as ensuring the sockets are closed and any resources that may be- associated with the sockets are properly disposed of.-- [Notes]-- * 'System.IO.Splice.Linux.c_splice', the Linux-only system call, is not- a terminal infinite loop and can be safely interleaved by other IO- operations on sockets or socket handles.- -}-- splice- , ChunkSize- , zeroCopy-- -- * Combinators for Exception Handling- , tryWith- , try_-- -- * Implementation Primitives- {- | Infinite loops used in the cross-platform implementation of 'splice'.- -}-- , hSplice-#ifdef LINUX_SPLICE- , fdSplice-#endif-- ) where---import Data.Word-import Foreign.Ptr--import System.IO-import Network.Socket-import Control.Monad-import Control.Exception-import Foreign.Marshal.Alloc--#ifdef LINUX_SPLICE-import Data.Int-import Data.Bits-import System.Posix.IO-import Unsafe.Coerce-import Foreign.C.Error-import System.Posix.Types-import System.Posix.Internals-import qualified System.IO.Splice.Linux as L-#else-import Data.Maybe-#endif---------------------------------------------------------------------------------------- | Indicates whether 'splice' uses zero-copy system calls or the portable user --- space Haskell implementation.-zeroCopy :: Bool -- ^ @True@ if 'splice' uses zero-copy system calls;- -- otherwise, false.-zeroCopy =-#ifdef LINUX_SPLICE- True-#else- False-#endif----- | The numeric type to recommend chunk sizes for moving data between sockets--- used by both zero-copy and portable implementations of 'splice'.-type ChunkSize =-#ifdef LINUX_SPLICE- L.ChunkSize-#else- Int-#endif---throwRecv0 :: a+-- | Implementation. +-- +-- Module : Network.Socket.Splice.Internal +-- Copyright : (c) Cetin Sert 2012 +-- License : BSD3 +-- Maintainer : fusion@corsis.eu +-- Stability : stable +-- Portability : works on all operating systems + + +#ifdef LINUX_SPLICE +#include <fcntl.h> +#endif +{-# LANGUAGE CPP, ForeignFunctionInterface #-} + + +module Network.Socket.Splice.Internal ( + + -- * 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. + + 'splice' and its implementation primitives 'hSplice' and 'fdSplice' are + /infinite/ loops that are intended to be used with + 'Control.Concurrent.forkIO' and exception handlers. 'splice' is a + terminal operation; it cannot be interleaved by other IO operations on + its sockets or handles. + + [Initiate bi-directional continuous data transfer between two sockets:] + + > void . forkIO . tryWith handler $! splice void 1024 (sourceSocket, _) (targetSocket, _) + > void . forkIO . tryWith handler $! splice void 1024 (targetSocket, _) (sourceSocket, _) + + where @handler@ is an IO operation that would do the necessary clean up – + such as ensuring the sockets are closed and any resources that may be + associated with the sockets are properly disposed of. + + [Notes] + + * 'System.IO.Splice.Linux.c_splice', the Linux-only system call, is not + a terminal infinite loop and can be safely interleaved by other IO + operations on sockets or socket handles. + -} + + splice + , ChunkSize + , zeroCopy + + -- * Combinators for Exception Handling + , tryWith + , try_ + + -- * Implementation Primitives + {- | Infinite loops used in the cross-platform implementation of 'splice'. -} + + , hSplice +#ifdef LINUX_SPLICE + , fdSplice +#endif + + ) where + + +import Data.Word +import Foreign.Ptr + +import System.IO +import Network.Socket +import Control.Monad +import Control.Exception +import Foreign.Marshal.Alloc + +#ifdef LINUX_SPLICE +import Data.Int +import Data.Bits +import System.Posix.IO +import Unsafe.Coerce +import Foreign.C.Error +import System.Posix.Types +import System.Posix.Internals +import qualified System.IO.Splice.Linux as L +#else +import Data.Maybe +#endif + + +---------------------------------------------------------------------------------------------------- + + +-- | Indicates whether 'splice' uses zero-copy system calls or the portable user +-- space Haskell implementation. +zeroCopy :: Bool -- ^ @True@ if 'splice' uses zero-copy system calls; otherwise, false. +zeroCopy = +#ifdef LINUX_SPLICE + True +#else + False +#endif + + +-- | The numeric type to recommend chunk sizes for moving data between sockets +-- used by both zero-copy and portable implementations of 'splice'. +type ChunkSize = +#ifdef LINUX_SPLICE + L.ChunkSize +#else + Int +#endif + + +----------------------------------------------------------------------------------------------SPLICE + + +-- | Pipes data from one socket to another in an /infinite loop/. +-- +-- 'splice' currently has two implementations: +-- +-- [on GNU\/Linux using 'fdSplice' ≅] +-- +-- > splice len (sIn, _ ) (sOut, _ ) = ... fdSplice ... +-- +-- [on all other operating systems using 'hSplice' ≅] +-- +-- > splice len (_ , Just hIn) (_ , Just hOut) = ... hSplice ... +-- +-- [Notes] +-- +-- * 'fdSplice' and 'fdSplice' implementation of 'splice' are only available +-- on GNU\/Linux. +-- +-- * 'hSplice' is always available and the 'hSplice' implementation of +-- 'splice' can be forced on GNU\/Linux by defining the @portable@ flag at +-- compile time. +-- +-- * 'hSplice' implementation requires handles in 'NoBuffering' mode. +-- +-- * 'splice' is a terminal loop on two sockets and once entered its sockets +-- and handles cannot be interleaved by other IO operations. +-- +splice + :: ChunkSize -- ^ maximal chunk size. + -> (Socket, Maybe Handle) -- ^ source socket and possibly its opened handle. + -> (Socket, Maybe Handle) -- ^ target socket and possibly its opened handle. + -> IO () -- ^ infinite loop. +#ifdef LINUX_SPLICE +splice len (sIn, _ ) (sOut, _ ) = do +#else +splice len (_ , hIn) (_ , hOut) = do +#endif +#ifdef LINUX_SPLICE + let s = Fd $! fdSocket sIn + let t = Fd $! fdSocket sOut + fdSplice len s t +#else + let s = fromJust hIn + let t = fromJust hOut + hSplice (fromIntegral len) s t +#endif + + +--------------------------------------------------------------------------------------------FDSPLICE + + +#ifdef LINUX_SPLICE + +{- | GNU\/Linux @splice()@ system call loop. + + 1. creates a pipe in kernel address space + + 2. uses it until the loop terminates by exception + + 3. closes the pipe and returns +-} +fdSplice :: ChunkSize -> Fd -> Fd -> IO () +fdSplice len s@(Fd fdIn) t@(Fd fdOut) = do + + (r,w) <- createPipe + let n = nullPtr + let u = unsafeCoerce :: (#type ssize_t) -> (#type size_t) + let check = throwErrnoIfMinus1 "Network.Socket.Splice.splice" + let flags = L.sPLICE_F_MOVE .|. L.sPLICE_F_MORE + let setNonBlockingMode v = do setNonBlockingFD fdIn v + setNonBlockingFD fdOut v + setNonBlockingMode False + + finally + (forever $! do + bytes <- check $! L.c_splice s n w n len flags + if bytes > 0 + then L.c_splice r n t n (u bytes) flags + else throwRecv0) + (do closeFd r + closeFd w + try_ $! setNonBlockingMode True) + +#endif + + +---------------------------------------------------------------------------------------------HSPLICE + + +{- | The portable Haskell loop. + + 1. allocates a /single/ memory buffer in user address space + + 2. uses it until the loop terminates by exception + + 3. frees the buffer and returns + + [Notes] + + * the socket handles are required to be in 'NoBuffering' mode. +-} +hSplice :: Int -> Handle -> Handle -> IO () +hSplice len s t = do + + a <- mallocBytes len :: IO (Ptr Word8) + + finally + (forever $! do + bytes <- hGetBufSome s a len + if bytes > 0 + then hPutBuf t a bytes + else throwRecv0) + (free a) + + +------------------------------------------------------------------------------------------EXCEPTIONS + + +-- | Similar to 'Control.Exception.Base.try' but used when an obvious exception +-- is expected and can be handled easily. Unlike 'finally' exceptions are +-- /NOT/ rethrown once handled. +tryWith + :: (SomeException -> IO a) -- ^ exception handler. + -> IO a -- ^ action to run which can throw /any/ exception. + -> IO a -- ^ new action where all exceptions are handled by the single handler. +tryWith h a = try a >>= \r -> case r of Left x -> h x; Right y -> return y + + +-- | Similar to 'Control.Exception.Base.try' but used when an obvious exception +-- is expected which can be safely ignored. +try_ + :: IO () -- ^ action to run which can throw /any/ exception. + -> IO () -- ^ new action where exceptions are silenced. +try_ a = (try a :: IO (Either SomeException ())) >> return () + + +throwRecv0 :: a throwRecv0 = error "Network.Socket.Splice.splice ended"---- | Pipes data from one socket to another in an /infinite loop/.------ 'splice' currently has two implementations:------ [on GNU\/Linux using 'fdSplice' ≅]------ > splice len (sIn, _ ) (sOut, _ ) = ... fdSplice ...------ [on all other operating systems using 'hSplice' ≅]------ > splice len (_ , Just hIn) (_ , Just hOut) = ... hSplice ...------ [Notes]------ * 'fdSplice' and 'fdSplice' implementation of 'splice' are only available--- on GNU\/Linux.------ * 'hSplice' is always available and the 'hSplice' implementation of--- 'splice' can be forced on GNU\/Linux by defining the @portable@ flag at--- compile time.------ * 'hSplice' implementation requires handles in 'NoBuffering' mode.------ * 'splice' is a terminal loop on two sockets and once entered its sockets--- and handles cannot be interleaved by other IO operations.----splice- :: ChunkSize -- ^ chunk size.- -> (Socket, Maybe Handle) -- ^ source socket and possibly its opened handle.- -> (Socket, Maybe Handle) -- ^ target socket and possibly its opened handle.- -> IO () -- ^ infinite loop.-#ifdef LINUX_SPLICE-splice len (sIn, _ ) (sOut, _ ) = do-#else-splice len (_ , hIn) (_ , hOut) = do-#endif-#ifdef LINUX_SPLICE- let s = Fd $ fdSocket sIn- let t = Fd $ fdSocket sOut- fdSplice len s t-#else- let s = fromJust hIn- let t = fromJust hOut- hSplice (fromIntegral len) s t-#endif----#ifdef LINUX_SPLICE--{- | GNU\/Linux @splice()@ system call loop.-- 1. creates a pipe in kernel address space-- 2. uses it until the loop terminates by exception-- 3. closes the pipe and returns--}-fdSplice :: ChunkSize -> Fd -> Fd -> IO ()-fdSplice len s@(Fd fdIn) t@(Fd fdOut) = do-- (r,w) <- createPipe- let n = nullPtr - let u = unsafeCoerce :: (#type ssize_t) -> (#type size_t)- let check = throwErrnoIfMinus1 "Network.Socket.Splice.splice"- let flags = L.sPLICE_F_MOVE .|. L.sPLICE_F_MORE- let setNonBlockingMode v = do setNonBlockingFD fdIn v- setNonBlockingFD fdOut v- setNonBlockingMode False-- finally- (forever $ do - bytes <- check $ L.c_splice s n w n len flags- if bytes > 0- then L.c_splice r n t n (u bytes) flags- else throwRecv0)- (do closeFd r- closeFd w- try_ $ setNonBlockingMode True)--#endif----{- | The portable Haskell loop.-- 1. allocates a /single/ memory buffer in user address space-- 2. uses it until the loop terminates by exception-- 3. frees the buffer and returns-- [Notes]-- * the socket handles are required to be in 'NoBuffering' mode.--} -hSplice :: Int -> Handle -> Handle -> IO ()-hSplice len s t = do-- a <- mallocBytes len :: IO (Ptr Word8)-- finally- (forever $ do- bytes <- hGetBufSome s a len- if bytes > 0- then hPutBuf t a bytes- else throwRecv0)- (free a)----- | Similar to 'Control.Exception.Base.try' but used when an obvious exception--- is expected and can be handled easily. Unlike 'finally' exceptions are--- /NOT/ rethrown once handled.-tryWith- :: (SomeException -> IO a) -- ^ exception handler.- -> IO a -- ^ action to run which can throw /any/ exception.- -> IO a -- ^ new action where all exceptions are handled by the single handler.-tryWith h a = try a >>= \r -> case r of Left x -> h x; Right y -> return y----- | Similar to 'Control.Exception.Base.try' but used when an obvious exception--- is expected which can be safely ignored.-try_- :: IO () -- ^ action to run which can throw /any/ exception.- -> IO () -- ^ new action where exceptions are silenced.-try_ a = (try a :: IO (Either SomeException ())) >> return ()
src/System/IO/Splice/Linux.hsc view
@@ -1,77 +1,78 @@-{- | Exposes the GNU\/Linux system call @splice()@: <http://kerneltrap.org/node/6505>.-- /This module is only available (compiled & exposed) on GNU/\//Linux./--}--- --- Module : System.IO.Splice.Linux--- Copyright : (c) Cetin Sert 2012--- License : BSD3--- Maintainer : fusion@corsis.eu--- Stability : stable--- Portability : GNU\/Linux-only--#include <fcntl.h>-{-# LANGUAGE CPP #-}-{-# LANGUAGE ForeignFunctionInterface #-}--module System.IO.Splice.Linux (-- c_splice- , ChunkSize- , sPLICE_F_MOVE- , sPLICE_F_MORE- , sPLICE_F_NONBLOCK-- ) where---import Data.Int-import Data.Word-import Foreign.Ptr-import Foreign.C.Types-import System.Posix.Types----- | The numeric type used by 'c_splice' for chunk size recommendations when--- moving data.-type ChunkSize = (#type size_t)---- | 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 descriptor @fd_out@,--- where one of the descriptors must refer to a pipe.------ 'c_splice' is /NOT/ a loop and needs to be called repeatedly.------ For an example, see 'Network.Socket.Splice.Internal.splice'.-foreign import ccall "splice"- c_splice- :: Fd -- ^ @fd_in@.- -> Ptr (#type loff_t) -- ^ @off_in@.- -> Fd -- ^ @fd_out@.- -> Ptr (#type loff_t) -- ^ @off_out@.- -> ChunkSize -- ^ @len@.- -> Word -- ^ @flags@.- -> IO (#type ssize_t) -- ^ number of bytes moved if successful; otherwise -1.----- | Attempt to move pages instead of copying. This is only a hint to the--- kernel: pages may stil be copied (/in kernel address space/) 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 'c_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 'c_splice' pipe operations--- nonblocking, but 'c_splice' may nevertheless block because the file--- descriptors that are 'c_splice'd to\/from may block (unless they have the--- @O_NONBLOCK@ flag set).-sPLICE_F_NONBLOCK :: Word+{- | Exposes the GNU\/Linux system call @splice()@: <http://kerneltrap.org/node/6505>. + + /This module is only available (compiled & exposed) on GNU/\//Linux./ +-} +-- +-- Module : System.IO.Splice.Linux +-- Copyright : (c) Cetin Sert 2012 +-- License : BSD3 +-- Maintainer : fusion@corsis.eu +-- Stability : stable +-- Portability : GNU\/Linux-only + + +#include <fcntl.h> +{-# LANGUAGE CPP, ForeignFunctionInterface #-} + + +module System.IO.Splice.Linux ( + + c_splice + , ChunkSize + , sPLICE_F_MOVE + , sPLICE_F_MORE + , sPLICE_F_NONBLOCK + + ) where + + +import Data.Int +import Data.Word +import Foreign.Ptr +import Foreign.C.Types +import System.Posix.Types + + +-- | The numeric type used by 'c_splice' for chunk size recommendations when +-- moving data. +type ChunkSize = (#type size_t) + +-- | 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 descriptor @fd_out@, +-- where one of the descriptors must refer to a pipe. +-- +-- 'c_splice' is /NOT/ a loop and needs to be called repeatedly. +-- +-- For an example, see 'Network.Socket.Splice.Internal.splice'. +foreign import ccall "splice" + c_splice + :: Fd -- ^ @fd_in@. + -> Ptr (#type loff_t) -- ^ @off_in@. + -> Fd -- ^ @fd_out@. + -> Ptr (#type loff_t) -- ^ @off_out@. + -> ChunkSize -- ^ @len@. + -> Word -- ^ @flags@. + -> IO (#type ssize_t) -- ^ number of bytes moved if successful; otherwise -1. + + +-- | Attempt to move pages instead of copying. This is only a hint to the +-- kernel: pages may stil be copied (/in kernel address space/) 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 'c_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 'c_splice' pipe operations +-- nonblocking, but 'c_splice' may nevertheless block because the file +-- descriptors that are 'c_splice'd to\/from may block (unless they have the +-- @O_NONBLOCK@ flag set). +sPLICE_F_NONBLOCK :: Word sPLICE_F_NONBLOCK = (#const "SPLICE_F_NONBLOCK")