packages feed

splice (empty) → 0.1

raw patch · 4 files changed

+263/−0 lines, 4 filesdep +basedep +networkdep +unixsetup-changed

Dependencies added: base, network, unix

Files

+ LICENSE view
@@ -0,0 +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.
+ Setup.lhs view
@@ -0,0 +1,6 @@+#!/usr/bin/runhaskell 
+> module Main where
+> import Distribution.Simple
+> main :: IO ()
+> main = defaultMain
+
+ splice.cabal view
@@ -0,0 +1,53 @@+name:          splice+version:       0.1+stability:     stable on Linux, experimental on other operating systems+synopsis:      Socket to Socket Data Splicing+description:   A library that 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.+               .+               This work has been funded by Corsis Research and is used+               in PortFusion: <http://portfusion.sf.net>+license:       BSD3+license-file:  LICENSE+author:        Cetin Sert <fusion@corsis.eu>+maintainer:    Cetin Sert <fusion@corsis.eu>+homepage:      http://fusion.corsis.eu+category:      Network+build-type:    Simple+cabal-version: >=1.2+copyright:     Copyright © 2012 Cetin Sert+tested-with:   GHC >= 7.4.3+++flag portable+    description: explicitly enable portable splice implemented in Haskell+    default    : False+++library++    hs-source-dirs:  src++    exposed-modules: Network.Socket.Splice++    if os(linux) && !flag(portable)+      build-depends: base    >= 4 && <= 6,+                     network >= 2 && <= 4,+                     unix    >= 2 && <= 4+      cpp-options: -DLINUX_SPLICE+      ghc-options: -O2 -O3 -fllvm -optlo-O3+    else+      build-depends: base    >= 4 && <= 6,+                     network >= 2 && <= 4+      cpp-options: -ULINUX_SPLICE+      ghc-options: -O2 -O3
+ src/Network/Socket/Splice.hsc view
@@ -0,0 +1,173 @@+-- |+-- Module      : Network.Socket.Splice+-- Copyright   : (c) Cetin Sert 2012+-- License     : BSD-style+--+-- Maintainer  : fusion@corsis.eu+-- Stability   : stable+-- Portability : GHC-only++#ifdef LINUX_SPLICE+#include <fcntl.h>+{-# LANGUAGE CPP #-}+{-# LANGUAGE ForeignFunctionInterface #-}+#endif++module Network.Socket.Splice (+    Length+  , zeroCopy+  , loopSplice+#ifdef LINUX_SPLICE+  , c_splice+#endif+  ) where++import Data.Word+import Foreign.Ptr++import Network.Socket+import Control.Monad+import Control.Exception+import System.IO+import System.Posix.Types+import System.Posix.Internals+import GHC.IO.Handle.FD++#ifdef LINUX_SPLICE+import Data.Int+import Data.Bits+import Unsafe.Coerce+import Foreign.C.Types+import Foreign.C.Error+import System.Posix.IO+#else+import Foreign.Marshal.Alloc+#endif+++-- | Indicates whether 'loopSplice' uses zero copy system calls+--   or the portable user mode Haskell substitue implementation.+zeroCopy :: Bool -- ^ True: system calls; otherwise: portable.+zeroCopy =+#ifdef LINUX_SPLICE+  True+#else+  False+#endif+++--------------------------------------------------------------------------------+++type Length =+#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.+--   On Linux this happens in kernel space with+--   zero copying, between kernel and user space.+--   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++  let throwRecv0 = error "Network.Socket.Splice.splice ended"++  let fdIn  = fdSocket sIn+  let fdOut = fdSocket sOut ++#ifdef LINUX_SPLICE++  print "LINUX-SPLICE"++  (r,w) <- createPipe     -- r: read  end of pipe+  print ('+',r,w)         -- w: write end of pipe+  let s = Fd fdIn         -- s: source socket+  let t = Fd fdOut        -- t: target socket+  let n = nullPtr  +  let u = unsafeCoerce :: (#type ssize_t) -> (#type size_t)+  let check = throwErrnoIfMinus1 "Network.Socket.Splice.splice"+  let flags = sPLICE_F_MOVE .|. sPLICE_F_MORE+  let setNonBlockingMode v = do setNonBlockingFD fdIn  v+                                setNonBlockingFD fdOut v++  setNonBlockingMode False+  finally+    (forever $ do +       bytes <- check $ c_splice s n w n    len    flags+       if bytes > 0+         then           c_splice r n t n (u bytes) flags+         else           throwRecv0)+    (do closeFd r+        closeFd w+        try_ $ setNonBlockingMode True+        print ('-',r,w))++#else++  s <- fdToHandle fdIn+  t <- fdToHandle fdOut+  hSetBuffering s NoBuffering+  hSetBuffering t NoBuffering+  a <- mallocBytes len :: IO (Ptr Word8)++  print "PORTABLE-SPLICE"++  finally+    (forever $ do+       bytes <-   hGetBufSome s a len+       if bytes > 0+         then     hPutBuf     t a bytes+         else     throwRecv0)+    (do free a+        try_ $ hClose s+        try_ $ hClose t)++#endif+++--------------------------------------------------------------------------------+++#ifdef LINUX_SPLICE+-- SPLICE++-- fcntl.h+-- ssize_t splice(+--   int          fd_in,+--   loff_t*      off_in,+--   int          fd_out,+--   loff_t*      off_out,+--   size_t       len,+--   unsigned int flags+-- );++foreign import ccall "splice"+  c_splice+  :: Fd+  -> Ptr (#type loff_t)+  -> Fd+  -> Ptr (#type loff_t)+  -> (#type size_t)+  -> Word+  -> IO (#type ssize_t)++sPLICE_F_MOVE :: Word+sPLICE_F_MOVE = (#const "SPLICE_F_MOVE")++sPLICE_F_MORE :: Word+sPLICE_F_MORE = (#const "SPLICE_F_MORE")+#endif