{-# LANGUAGE OverloadedStrings #-} module Network.Socket.ByteString.Lazy.Posix ( -- * Send data to a socket send, sendAll, ) where import qualified Data.ByteString.Lazy as L import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import Foreign.Marshal.Array (allocaArray) import Network.Socket.ByteString.IO (waitWhen0) import Network.Socket.ByteString.Internal (c_writev) import Network.Socket.Imports import Network.Socket.Internal import Network.Socket.Posix.IOVec (IOVec (IOVec)) import Network.Socket.Types -- ----------------------------------------------------------------------------- -- Sending send :: Socket -- ^ Connected socket -> L.ByteString -- ^ Data to send -> IO Int64 -- ^ Number of bytes sent send s lbs = do let cs = take maxNumChunks (L.toChunks lbs) len = length cs siz <- withFdSocket s $ \fd -> allocaArray len $ \ptr -> withPokes cs ptr $ \niovs -> throwSocketErrorWaitWrite s "writev" $ c_writev fd ptr niovs return $ fromIntegral siz where withPokes ss p f = loop ss p 0 0 where loop (c : cs) q k niovs | k < maxNumBytes = unsafeUseAsCStringLen c $ \(ptr, len) -> do poke q $ IOVec (castPtr ptr) (fromIntegral len) loop cs (q `plusPtr` sizeOf (IOVec nullPtr 0)) (k + fromIntegral len) (niovs + 1) | otherwise = f niovs loop _ _ _ niovs = f niovs maxNumBytes = 4194304 :: Int -- maximum number of bytes to transmit in one system call maxNumChunks = 1024 :: Int -- maximum number of chunks to transmit in one system call sendAll :: Socket -- ^ Connected socket -> L.ByteString -- ^ Data to send -> IO () sendAll _ "" = return () sendAll s bs0 = loop bs0 where loop bs = do -- "send" throws an exception. sent <- send s bs waitWhen0 (fromIntegral sent) s when (sent /= L.length bs) $ loop $ L.drop sent bs