{-# LANGUAGE ForeignFunctionInterface #-} module Network.MoeSocks.Internal.Socket where import Control.Monad (liftM, when) import Data.ByteString (ByteString) import qualified Data.ByteString as S import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import Foreign.C.Types (CSize(..), CInt(..)) import Foreign.Ptr (Ptr) import Network.Socket (Socket(MkSocket), SockAddr, ) import Network.Socket.ByteString (sendAll) import Network.Socket.Internal (withSockAddr) foreign import ccall unsafe "sendto" c_sendto :: CInt -> Ptr a -> CSize -> CInt -> Ptr SockAddr -> CInt -> IO CInt -- | 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. sendBufToWithFlagNoRetry :: Socket -- (possibly) bound/connected Socket -> Ptr a -> Int -- Data to send -> SockAddr -> Int -> IO Int -- Number of Bytes sent sendBufToWithFlagNoRetry (MkSocket s _family _stype _protocol _status) ptr nbytes addr flags = do withSockAddr addr $ \p_addr sz -> do liftM fromIntegral $ c_sendto s ptr (fromIntegral $ nbytes) (fromIntegral flags) p_addr (fromIntegral sz) sendToWithFlagNoRetry :: Socket -- ^ Socket -> ByteString -- ^ Data to send -> SockAddr -- ^ Recipient address -> Int -> IO Int -- ^ Number of bytes sent sendToWithFlagNoRetry sock xs addr flags = unsafeUseAsCStringLen xs $ \(str, len) -> sendBufToWithFlagNoRetry sock str len addr flags sendAllToFastOpen :: Socket -- ^ Socket -> ByteString -- ^ Data to send -> SockAddr -- ^ Recipient address -> IO () sendAllToFastOpen sock xs addr = do let _MSG_FASTOPEN = 0x20000000 sent <- sendToWithFlagNoRetry sock xs addr _MSG_FASTOPEN when (sent < S.length xs) $ sendAll sock (S.drop sent xs)