{-# LINE 1 "src/Network/Socket/SendFile/Linux.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "src/Network/Socket/SendFile/Linux.hsc" #-}
-- | Linux system-dependent code for 'sendfile'.
module Network.Socket.SendFile.Linux (_sendFile) where
import Data.Int
import Data.Word
import Foreign.C.Error (eAGAIN, getErrno, throwErrno)
import Foreign.Marshal (alloca)
import Foreign.Ptr (Ptr)
import Foreign.Storable(poke)
import System.Posix.Types (Fd)
import Control.Concurrent (threadWaitWrite)


{-# LINE 14 "src/Network/Socket/SendFile/Linux.hsc" #-}

_sendFile :: Fd -> Fd -> Int64 -> Int64 -> IO ()
_sendFile out_fd in_fd off count = do
    alloca $ \poff -> do
    poke poff off
    rsendfile out_fd in_fd poff count

rsendfile :: Fd -> Fd -> Ptr Int64 -> Int64 -> IO ()
rsendfile _      _     _    0         = return ()
rsendfile out_fd in_fd poff remaining = do
    let bytes = min remaining maxBytes
    sbytes <- sendfile out_fd in_fd poff bytes
    rsendfile out_fd in_fd poff (remaining - sbytes)
    
sendfile :: Fd -> Fd -> Ptr Int64 -> Int64 -> IO Int64
sendfile out_fd in_fd poff bytes = do
    threadWaitWrite out_fd
    sbytes <- c_sendfile out_fd in_fd poff (fromIntegral bytes)
    if sbytes <= -1
      then do errno <- getErrno
              if errno == eAGAIN
                then sendfile out_fd in_fd poff bytes
                else throwErrno "Network.Socket.SendFile.Linux"
      else return (fromIntegral sbytes)

-- max num of bytes in one send
maxBytes :: Int64
maxBytes = fromIntegral (maxBound :: (Int32))
{-# LINE 42 "src/Network/Socket/SendFile/Linux.hsc" #-}

-- sendfile64 gives LFS support
foreign import ccall unsafe "sendfile64" c_sendfile
    :: Fd -> Fd -> Ptr (Int64) -> (Word32) -> IO (Int32)
{-# LINE 46 "src/Network/Socket/SendFile/Linux.hsc" #-}