content: {-# LANGUAGE CPP #-}
  -- |
  -- 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.  For detailed
  -- documentation, consult your favorite POSIX socket reference. All functions
  -- communicate failures by converting the error number to an
  -- 'System.IO.Error.IOError'.
  --
  -- This module is made to be imported with "Network.Socket" like so:
  --
  -- > import Network.Socket
  -- > import Network.Socket.ByteString.Lazy
  -- > import Prelude hiding (getContents)
  --
  module Network.Socket.ByteString.Lazy (
      -- * Send data to a socket
      send
    , sendAll
      -- * Receive data from a socket
    , getContents
    , recv
    ) where
  
  import           Data.ByteString.Lazy.Internal (ByteString(..), defaultChunkSize)
  import           Network.Socket                (ShutdownCmd (..), shutdown)
  import           Prelude                       hiding (getContents)
  import           System.IO.Unsafe              (unsafeInterleaveIO)
  import           System.IO.Error               (catchIOError)
  
  #if defined(mingw32_HOST_OS)
  import Network.Socket.ByteString.Lazy.Windows  (send, sendAll)
  #else
  import Network.Socket.ByteString.Lazy.Posix    (send, sendAll)
  #endif
  
  import qualified Data.ByteString               as S
  import qualified Network.Socket.ByteString     as N
  import           Network.Socket.Imports
  import           Network.Socket.Types
  
  -- -----------------------------------------------------------------------------
  -- 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 s = loop
    where
      loop = unsafeInterleaveIO $ do
          sbs <- N.recv s defaultChunkSize
          if S.null sbs
              then do
                shutdown s ShutdownReceive `catchIOError` const (return ())
                return Empty
              else Chunk sbs <$> 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 s nbytes = chunk <$> N.recv s (fromIntegral nbytes)
    where
      chunk k | S.null k  = Empty
              | otherwise = Chunk k Empty
  