{-# LINE 1 "Network/Socket/Buffer.hsc" #-}
{-# LANGUAGE CPP #-}

#include "HsNetDef.h"

{-# LINE 7 "Network/Socket/Buffer.hsc" #-}

module Network.Socket.Buffer (
    sendBufTo
  , sendBuf
  , recvBufFrom
  , recvBuf
  , recvBufNoWait
  ) where


{-# LINE 17 "Network/Socket/Buffer.hsc" #-}
import Foreign.C.Error (getErrno, eAGAIN, eWOULDBLOCK)

{-# LINE 19 "Network/Socket/Buffer.hsc" #-}
import Foreign.Marshal.Alloc (alloca)
import GHC.IO.Exception (IOErrorType(InvalidArgument))
import System.IO.Error (mkIOError, ioeSetErrorString, catchIOError)


{-# LINE 26 "Network/Socket/Buffer.hsc" #-}

import Network.Socket.Imports
import Network.Socket.Internal
import Network.Socket.Name
import Network.Socket.Types

-- | Send data to the socket.  The recipient can be specified
-- explicitly, so the socket need not be in a connected state.
-- Returns the number of bytes sent.  Applications are responsible for
-- ensuring that all data has been sent.
sendBufTo :: SocketAddress sa =>
             Socket -- (possibly) bound/connected Socket
          -> Ptr a
          -> Int         -- Data to send
          -> sa
          -> IO Int      -- Number of Bytes sent
sendBufTo :: Socket -> Ptr a -> Int -> sa -> IO Int
sendBufTo Socket
s Ptr a
ptr Int
nbytes sa
sa =
  sa -> (Ptr sa -> Int -> IO Int) -> IO Int
forall sa a.
SocketAddress sa =>
sa -> (Ptr sa -> Int -> IO a) -> IO a
withSocketAddress sa
sa ((Ptr sa -> Int -> IO Int) -> IO Int)
-> (Ptr sa -> Int -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr sa
p_sa Int
siz -> CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt -> Int) -> IO CInt -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do
    Socket -> (CInt -> IO CInt) -> IO CInt
forall r. Socket -> (CInt -> IO r) -> IO r
withFdSocket Socket
s ((CInt -> IO CInt) -> IO CInt) -> (CInt -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \CInt
fd -> do
        let sz :: CInt
sz = Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
siz
            n :: CSize
n = Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbytes
            flags :: CInt
flags = CInt
0
        Socket -> String -> IO CInt -> IO CInt
forall a. (Eq a, Num a) => Socket -> String -> IO a -> IO a
throwSocketErrorWaitWrite Socket
s String
"Network.Socket.sendBufTo" (IO CInt -> IO CInt) -> IO CInt -> IO CInt
forall a b. (a -> b) -> a -> b
$
          CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> CInt -> IO CInt
forall a sa.
CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> CInt -> IO CInt
c_sendto CInt
fd Ptr a
ptr CSize
n CInt
flags Ptr sa
p_sa CInt
sz


{-# LINE 58 "Network/Socket/Buffer.hsc" #-}

-- | Send data to the socket. The socket must be connected to a remote
-- socket. Returns the number of bytes sent.  Applications are
-- responsible for ensuring that all data has been sent.
sendBuf :: Socket    -- Bound/Connected Socket
        -> Ptr Word8  -- Pointer to the data to send
        -> Int        -- Length of the buffer
        -> IO Int     -- Number of Bytes sent
sendBuf :: Socket -> Ptr Word8 -> Int -> IO Int
sendBuf Socket
s Ptr Word8
str Int
len = CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt -> Int) -> IO CInt -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do

{-# LINE 77 "Network/Socket/Buffer.hsc" #-}
    Socket -> (CInt -> IO CInt) -> IO CInt
forall r. Socket -> (CInt -> IO r) -> IO r
withFdSocket Socket
s ((CInt -> IO CInt) -> IO CInt) -> (CInt -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \CInt
fd -> do
        let flags :: CInt
flags = CInt
0
            clen :: CSize
clen = Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len
        Socket -> String -> IO CInt -> IO CInt
forall a. (Eq a, Num a) => Socket -> String -> IO a -> IO a
throwSocketErrorWaitWrite Socket
s String
"Network.Socket.sendBuf" (IO CInt -> IO CInt) -> IO CInt -> IO CInt
forall a b. (a -> b) -> a -> b
$
          CInt -> Ptr Word8 -> CSize -> CInt -> IO CInt
forall a. CInt -> Ptr a -> CSize -> CInt -> IO CInt
c_send CInt
fd Ptr Word8
str CSize
clen CInt
flags

{-# LINE 83 "Network/Socket/Buffer.hsc" #-}

-- | Receive data from the socket, writing it into buffer instead of
-- creating a new string.  The socket need not be in a connected
-- state. Returns @(nbytes, address)@ where @nbytes@ is the number of
-- bytes received and @address@ is a 'SockAddr' representing the
-- address of the sending socket.
--
-- If the first return value is zero, it means EOF.
--
-- For 'Stream' sockets, the second return value would be invalid.
--
-- NOTE: blocking on Windows unless you compile with -threaded (see
-- GHC ticket #1129)
recvBufFrom :: SocketAddress sa => Socket -> Ptr a -> Int -> IO (Int, sa)
recvBufFrom :: Socket -> Ptr a -> Int -> IO (Int, sa)
recvBufFrom Socket
s Ptr a
ptr Int
nbytes
    | Int
nbytes Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = IOError -> IO (Int, sa)
forall a. IOError -> IO a
ioError (String -> IOError
mkInvalidRecvArgError String
"Network.Socket.recvBufFrom")
    | Bool
otherwise = (Ptr sa -> Int -> IO (Int, sa)) -> IO (Int, sa)
forall sa a. SocketAddress sa => (Ptr sa -> Int -> IO a) -> IO a
withNewSocketAddress ((Ptr sa -> Int -> IO (Int, sa)) -> IO (Int, sa))
-> (Ptr sa -> Int -> IO (Int, sa)) -> IO (Int, sa)
forall a b. (a -> b) -> a -> b
$ \Ptr sa
ptr_sa Int
sz -> (Ptr CInt -> IO (Int, sa)) -> IO (Int, sa)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CInt -> IO (Int, sa)) -> IO (Int, sa))
-> (Ptr CInt -> IO (Int, sa)) -> IO (Int, sa)
forall a b. (a -> b) -> a -> b
$ \Ptr CInt
ptr_len ->
        Socket -> (CInt -> IO (Int, sa)) -> IO (Int, sa)
forall r. Socket -> (CInt -> IO r) -> IO r
withFdSocket Socket
s ((CInt -> IO (Int, sa)) -> IO (Int, sa))
-> (CInt -> IO (Int, sa)) -> IO (Int, sa)
forall a b. (a -> b) -> a -> b
$ \CInt
fd -> do
            Ptr CInt -> CInt -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr CInt
ptr_len (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
sz)
            let cnbytes :: CSize
cnbytes = Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbytes
                flags :: CInt
flags = CInt
0
            CInt
len <- Socket -> String -> IO CInt -> IO CInt
forall a. (Eq a, Num a) => Socket -> String -> IO a -> IO a
throwSocketErrorWaitRead Socket
s String
"Network.Socket.recvBufFrom" (IO CInt -> IO CInt) -> IO CInt -> IO CInt
forall a b. (a -> b) -> a -> b
$
                     CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> Ptr CInt -> IO CInt
forall a sa.
CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> Ptr CInt -> IO CInt
c_recvfrom CInt
fd Ptr a
ptr CSize
cnbytes CInt
flags Ptr sa
ptr_sa Ptr CInt
ptr_len
            sa
sockaddr <- Ptr sa -> IO sa
forall sa. SocketAddress sa => Ptr sa -> IO sa
peekSocketAddress Ptr sa
ptr_sa
                IO sa -> (IOError -> IO sa) -> IO sa
forall a. IO a -> (IOError -> IO a) -> IO a
`catchIOError` \IOError
_ -> Socket -> IO sa
forall sa. SocketAddress sa => Socket -> IO sa
getPeerName Socket
s
            (Int, sa) -> IO (Int, sa)
forall (m :: * -> *) a. Monad m => a -> m a
return (CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
len, sa
sockaddr)

-- | Receive data from the socket.  The socket must be in a connected
-- state. This function may return fewer bytes than specified.  If the
-- message is longer than the specified length, it may be discarded
-- depending on the type of socket.  This function may block until a
-- message arrives.
--
-- Considering hardware and network realities, the maximum number of
-- bytes to receive should be a small power of 2, e.g., 4096.
--
-- The return value is the length of received data. Zero means
-- EOF. Historical note: Version 2.8.x.y or earlier,
-- an EOF error was thrown. This was changed in version 3.0.
recvBuf :: Socket -> Ptr Word8 -> Int -> IO Int
recvBuf :: Socket -> Ptr Word8 -> Int -> IO Int
recvBuf Socket
s Ptr Word8
ptr Int
nbytes
 | Int
nbytes Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = IOError -> IO Int
forall a. IOError -> IO a
ioError (String -> IOError
mkInvalidRecvArgError String
"Network.Socket.recvBuf")
 | Bool
otherwise   = do

{-# LINE 133 "Network/Socket/Buffer.hsc" #-}
    CInt
len <- Socket -> (CInt -> IO CInt) -> IO CInt
forall r. Socket -> (CInt -> IO r) -> IO r
withFdSocket Socket
s ((CInt -> IO CInt) -> IO CInt) -> (CInt -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \CInt
fd ->
        Socket -> String -> IO CInt -> IO CInt
forall a. (Eq a, Num a) => Socket -> String -> IO a -> IO a
throwSocketErrorWaitRead Socket
s String
"Network.Socket.recvBuf" (IO CInt -> IO CInt) -> IO CInt -> IO CInt
forall a b. (a -> b) -> a -> b
$
             CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
c_recv CInt
fd (Ptr Word8 -> Ptr CChar
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
ptr) (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbytes) CInt
0{-flags-}

{-# LINE 137 "Network/Socket/Buffer.hsc" #-}
    return $ fromIntegral len

-- | Receive data from the socket. This function returns immediately
--   even if data is not available. In other words, IO manager is NOT
--   involved. The length of data is returned if received.
--   -1 is returned in the case of EAGAIN or EWOULDBLOCK.
--   -2 is returned in other error cases.
recvBufNoWait :: Socket -> Ptr Word8 -> Int -> IO Int
recvBufNoWait :: Socket -> Ptr Word8 -> Int -> IO Int
recvBufNoWait Socket
s Ptr Word8
ptr Int
nbytes = Socket -> (CInt -> IO Int) -> IO Int
forall r. Socket -> (CInt -> IO r) -> IO r
withFdSocket Socket
s ((CInt -> IO Int) -> IO Int) -> (CInt -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \CInt
fd -> do

{-# LINE 165 "Network/Socket/Buffer.hsc" #-}
    CInt
r <- CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
c_recv CInt
fd (Ptr Word8 -> Ptr CChar
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
ptr) (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbytes) CInt
0{-flags-}
    if CInt
r CInt -> CInt -> Bool
forall a. Ord a => a -> a -> Bool
>= CInt
0 then
        Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> IO Int) -> Int -> IO Int
forall a b. (a -> b) -> a -> b
$ CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
r
      else do
        Errno
err <- IO Errno
getErrno
        if Errno
err Errno -> Errno -> Bool
forall a. Eq a => a -> a -> Bool
== Errno
eAGAIN Bool -> Bool -> Bool
|| Errno
err Errno -> Errno -> Bool
forall a. Eq a => a -> a -> Bool
== Errno
eWOULDBLOCK then
            Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1)
          else
            Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
2)

{-# LINE 175 "Network/Socket/Buffer.hsc" #-}

mkInvalidRecvArgError :: String -> IOError
mkInvalidRecvArgError :: String -> IOError
mkInvalidRecvArgError String
loc = IOError -> String -> IOError
ioeSetErrorString (IOErrorType -> String -> Maybe Handle -> Maybe String -> IOError
mkIOError
                                    IOErrorType
InvalidArgument
                                    String
loc Maybe Handle
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing) String
"non-positive length"


{-# LINE 182 "Network/Socket/Buffer.hsc" #-}
foreign import ccall unsafe "send"
  c_send :: CInt -> Ptr a -> CSize -> CInt -> IO CInt

{-# LINE 190 "Network/Socket/Buffer.hsc" #-}
foreign import ccall unsafe "recv"
  c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
foreign import CALLCONV SAFE_ON_WIN "sendto"
  c_sendto :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> CInt -> IO CInt
foreign import CALLCONV SAFE_ON_WIN "recvfrom"
  c_recvfrom :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> Ptr CInt -> IO CInt