    {-# LINE 1 "Network/Socket/ByteString/Lazy.hsc" #-}
    {-# LANGUAGE BangPatterns, CPP, ForeignFunctionInterface #-}
    {-# LINE 2 "Network/Socket/ByteString/Lazy.hsc" #-}

    -- |
    -- Module      : Network.Socket.ByteString.Lazy
    -- Copyright   : (c) Bryan O'Sullivan 2009
    -- License     : BSD-style
    --
    -- Maintainer  : bos@serpentine.com
    -- Stability   : experimental
    -- Portability : POSIX, GHC
    --
    -- This module provides access to the BSD /socket/ interface.  This
    -- module is generally more efficient than the 'String' based network
    -- functions in 'Network.Socket'.  For detailed documentation, consult
    -- your favorite POSIX socket reference. All functions communicate
    -- failures by converting the error number to 'System.IO.IOError'.
    --
    -- This module is made to be imported with 'Network.Socket' like so:
    --
    -- > import Network.Socket hiding (send, sendTo, recv, recvFrom)
    -- > import Network.Socket.ByteString.Lazy
    -- > import Prelude hiding (getContents)
    --
    module Network.Socket.ByteString.Lazy
        (

    {-# LINE 27 "Network/Socket/ByteString/Lazy.hsc" #-}
        -- * Send data to a socket
          send
        , sendAll
        ,

    {-# LINE 32 "Network/Socket/ByteString/Lazy.hsc" #-}

        -- * Receive data from a socket
          getContents
        , recv
        ) where

    import Control.Monad (liftM)
    import Data.ByteString.Lazy.Internal (ByteString(..), defaultChunkSize)
    import Data.Int (Int64)
    import Network.Socket (Socket(..), ShutdownCmd(..), shutdown)
    import Prelude hiding (getContents)
    import System.IO.Unsafe (unsafeInterleaveIO)

    import qualified Data.ByteString as S
    import qualified Network.Socket.ByteString as N

    {-# LINE 49 "Network/Socket/ByteString/Lazy.hsc" #-}
    import Control.Monad (unless)
    import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
    import Foreign.Marshal.Array (allocaArray)
    import Foreign.Ptr (plusPtr)
    import Foreign.Storable (Storable(..))
    import Network.Socket.ByteString.IOVec (IOVec(IOVec))
    import Network.Socket.ByteString.Internal (c_writev)
    import Network.Socket.Internal

    import qualified Data.ByteString.Lazy as L

    import GHC.Conc (threadWaitWrite)

    {-# LINE 62 "Network/Socket/ByteString/Lazy.hsc" #-}

    {-# LINE 64 "Network/Socket/ByteString/Lazy.hsc" #-}
    -- -----------------------------------------------------------------------------
    -- Sending

    -- | Send data to the socket. The socket must be in a connected state.
    -- Returns the number of bytes sent. Applications are responsible for
    -- ensuring that all data has been sent.
    --
    -- Because a lazily generated 'ByteString' may be arbitrarily long,
    -- this function caps the amount it will attempt to send at 4MB.  This
    -- number is large (so it should not penalize performance on fast
    -- networks), but not outrageously so (to avoid demanding lazily
    -- computed data unnecessarily early).  Before being sent, the lazy
    -- 'ByteString' will be converted to a list of strict 'ByteString's
    -- with 'L.toChunks'; at most 1024 chunks will be sent.  /Unix only/.
    send :: Socket      -- ^ Connected socket
         -> ByteString  -- ^ Data to send
         -> IO Int64    -- ^ Number of bytes sent
    send sock@(MkSocket fd _ _ _ _) s = do
      let cs  = take maxNumChunks (L.toChunks s)
          len = length cs
      liftM fromIntegral . allocaArray len $ \ptr ->
        withPokes cs ptr $ \niovs ->
          throwSocketErrorWaitWrite sock "writev" $
            c_writev (fromIntegral fd) ptr niovs
      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 ptr (fromIntegral len)
                          loop cs (q `plusPtr` sizeOf (undefined :: IOVec))
                                  (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

    -- | Send data to the socket.  The socket must be in a connected
    -- state. This function continues to send data until either all data
    -- has been sent or an error occurs.  If there is an error, an
    -- exception is raised, and there is no way to determine how much data
    -- was sent.  /Unix only/.
    sendAll :: Socket      -- ^ Connected socket
            -> ByteString  -- ^ Data to send
            -> IO ()
    sendAll sock bs = do
      sent <- send sock bs
      let bs' = L.drop sent bs
      unless (L.null bs') $ sendAll sock bs'

    {-# LINE 114 "Network/Socket/ByteString/Lazy.hsc" #-}

    -- -----------------------------------------------------------------------------
    -- Receiving

    -- | Receive data from the socket.  The socket must be in a connected
    -- state.  Data is received on demand, in chunks; each chunk will be
    -- sized to reflect the amount of data received by individual 'recv'
    -- calls.
    --
    -- All remaining data from the socket is consumed.  When there is no
    -- more data to be received, the receiving side of the socket is shut
    -- down.  If there is an error and an exception is thrown, the socket
    -- is not shut down.
    getContents :: Socket         -- ^ Connected socket
                -> IO ByteString  -- ^ Data received
    getContents sock = loop where
      loop = unsafeInterleaveIO $ do
        s <- N.recv sock defaultChunkSize
        if S.null s
          then shutdown sock ShutdownReceive >> return Empty
          else Chunk s `liftM` loop

    -- | Receive data from the socket.  The socket must be in a connected
    -- state.  This function may return fewer bytes than specified.  If
    -- the received data is longer than the specified length, it may be
    -- discarded depending on the type of socket.  This function may block
    -- until a message arrives.
    --
    -- If there is no more data to be received, returns an empty 'ByteString'.
    recv :: Socket         -- ^ Connected socket
         -> Int64          -- ^ Maximum number of bytes to receive
         -> IO ByteString  -- ^ Data received
    recv sock nbytes = chunk `liftM` N.recv sock (fromIntegral nbytes) where
      chunk k
        | S.null k  = Empty
        | otherwise = Chunk k Empty