{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
#include "HsNetDef.h"
module Network.Socket.Internal
    (
    
      throwSocketError
    , throwSocketErrorCode
#if defined(mingw32_HOST_OS)
    , c_getLastError
#endif
    
    , throwSocketErrorIfMinus1_
    , throwSocketErrorIfMinus1Retry
    , throwSocketErrorIfMinus1Retry_
    , throwSocketErrorIfMinus1RetryMayBlock
#if defined(mingw32_HOST_OS)
    , throwSocketErrorIfMinus1ButRetry
#endif
    
    
    
    
    , throwSocketErrorWaitRead
    , throwSocketErrorWaitReadBut
    , throwSocketErrorWaitWrite
    
    , withSocketsDo
    
    , zeroMemory
    ) where
import GHC.Conc (threadWaitRead, threadWaitWrite)
#if defined(mingw32_HOST_OS)
import Control.Exception (evaluate)
import System.IO.Unsafe (unsafePerformIO)
# if __GLASGOW_HASKELL__ >= 707
import GHC.IO.Exception (IOErrorType(..))
# else
import GHC.IOBase (IOErrorType(..))
# endif
import System.IO.Error (ioeSetErrorString, mkIOError)
#else
import Foreign.C.Error (throwErrno, throwErrnoIfMinus1Retry,
                        throwErrnoIfMinus1RetryMayBlock, throwErrnoIfMinus1_,
                        Errno(..), errnoToIOError)
#endif
#if defined(mingw32_HOST_OS)
import Network.Socket.Cbits
#endif
import Network.Socket.Imports
import Network.Socket.Types
throwSocketError :: String  
                 -> IO a
throwSocketErrorCode :: String -> CInt -> IO a
throwSocketErrorIfMinus1_
    :: (Eq a, Num a)
    => String  
    -> IO a    
    -> IO ()
{-# SPECIALIZE throwSocketErrorIfMinus1_ :: String -> IO CInt -> IO () #-}
throwSocketErrorIfMinus1Retry
    :: (Eq a, Num a)
    => String  
    -> IO a    
    -> IO a
{-# SPECIALIZE throwSocketErrorIfMinus1Retry :: String -> IO CInt -> IO CInt #-}
throwSocketErrorIfMinus1Retry_
    :: (Eq a, Num a)
    => String  
    -> IO a    
    -> IO ()
throwSocketErrorIfMinus1Retry_ :: forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwSocketErrorIfMinus1Retry_ String
loc IO a
m =
    IO a -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO a -> IO ()) -> IO a -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO a -> IO a
forall a. (Eq a, Num a) => String -> IO a -> IO a
throwSocketErrorIfMinus1Retry String
loc IO a
m
{-# SPECIALIZE throwSocketErrorIfMinus1Retry_ :: String -> IO CInt -> IO () #-}
throwSocketErrorIfMinus1RetryMayBlock
    :: (Eq a, Num a)
    => String  
    -> IO b    
               
    -> IO a    
    -> IO a
{-# SPECIALIZE throwSocketErrorIfMinus1RetryMayBlock
        :: String -> IO b -> IO CInt -> IO CInt #-}
throwSocketErrorIfMinus1RetryMayBlockBut
    :: (Eq a, Num a)
    => (CInt -> Bool) 
    -> String         
    -> IO b           
                      
    -> IO a           
    -> IO a
{-# SPECIALIZE throwSocketErrorIfMinus1RetryMayBlock
        :: String -> IO b -> IO CInt -> IO CInt #-}
#if defined(mingw32_HOST_OS)
throwSocketErrorIfMinus1RetryMayBlock name _ act
  = throwSocketErrorIfMinus1Retry name act
throwSocketErrorIfMinus1RetryMayBlockBut exempt name _ act
  = throwSocketErrorIfMinus1ButRetry exempt name act
throwSocketErrorIfMinus1_ name act = do
  _ <- throwSocketErrorIfMinus1Retry name act
  return ()
throwSocketErrorIfMinus1ButRetry :: (Eq a, Num a) =>
                                    (CInt -> Bool) -> String -> IO a -> IO a
throwSocketErrorIfMinus1ButRetry exempt name act = do
  r <- act
  if (r == -1)
   then do
    rc <- c_getLastError
    if rc == wsaNotInitialized then do
        withSocketsDo (return ())
        r' <- act
        if (r' == -1)
           then throwSocketError name
           else return r'
      else
        if (exempt rc)
          then return r
          else throwSocketError name
   else return r
throwSocketErrorIfMinus1Retry
  = throwSocketErrorIfMinus1ButRetry (const False)
throwSocketErrorCode name rc = do
    pstr <- c_getWSError rc
    str  <- peekCString pstr
    ioError (ioeSetErrorString (mkIOError OtherError name Nothing Nothing) str)
throwSocketError name =
    c_getLastError >>= throwSocketErrorCode name
foreign import CALLCONV unsafe "WSAGetLastError"
  c_getLastError :: IO CInt
foreign import ccall unsafe "getWSErrorDescr"
  c_getWSError :: CInt -> IO (Ptr CChar)
#else
throwSocketErrorIfMinus1RetryMayBlock :: forall a b. (Eq a, Num a) => String -> IO b -> IO a -> IO a
throwSocketErrorIfMinus1RetryMayBlock String
name IO b
on_block IO a
act =
    String -> IO a -> IO b -> IO a
forall a b. (Eq a, Num a) => String -> IO a -> IO b -> IO a
throwErrnoIfMinus1RetryMayBlock String
name IO a
act IO b
on_block
throwSocketErrorIfMinus1RetryMayBlockBut :: forall a b.
(Eq a, Num a) =>
(CInt -> Bool) -> String -> IO b -> IO a -> IO a
throwSocketErrorIfMinus1RetryMayBlockBut CInt -> Bool
_exempt String
name IO b
on_block IO a
act =
    String -> IO a -> IO b -> IO a
forall a b. (Eq a, Num a) => String -> IO a -> IO b -> IO a
throwErrnoIfMinus1RetryMayBlock String
name IO a
act IO b
on_block
throwSocketErrorIfMinus1Retry :: forall a. (Eq a, Num a) => String -> IO a -> IO a
throwSocketErrorIfMinus1Retry = String -> IO a -> IO a
forall a. (Eq a, Num a) => String -> IO a -> IO a
throwErrnoIfMinus1Retry
throwSocketErrorIfMinus1_ :: forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwSocketErrorIfMinus1_ = String -> IO a -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_
throwSocketError :: forall a. String -> IO a
throwSocketError = String -> IO a
forall a. String -> IO a
throwErrno
throwSocketErrorCode :: forall a. String -> CInt -> IO a
throwSocketErrorCode String
loc CInt
errno =
    IOError -> IO a
forall a. IOError -> IO a
ioError (String -> Errno -> Maybe Handle -> Maybe String -> IOError
errnoToIOError String
loc (CInt -> Errno
Errno CInt
errno) Maybe Handle
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing)
#endif
throwSocketErrorWaitRead :: (Eq a, Num a) => Socket -> String -> IO a -> IO a
throwSocketErrorWaitRead :: forall a. (Eq a, Num a) => Socket -> String -> IO a -> IO a
throwSocketErrorWaitRead Socket
s String
name IO a
io = Socket -> (CInt -> IO a) -> IO a
forall r. Socket -> (CInt -> IO r) -> IO r
withFdSocket Socket
s ((CInt -> IO a) -> IO a) -> (CInt -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \CInt
fd ->
    String -> IO () -> IO a -> IO a
forall a b. (Eq a, Num a) => String -> IO b -> IO a -> IO a
throwSocketErrorIfMinus1RetryMayBlock String
name
      (Fd -> IO ()
threadWaitRead (Fd -> IO ()) -> Fd -> IO ()
forall a b. (a -> b) -> a -> b
$ CInt -> Fd
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
fd) IO a
io
throwSocketErrorWaitReadBut :: (Eq a, Num a) => (CInt -> Bool) -> Socket -> String -> IO a -> IO a
throwSocketErrorWaitReadBut :: forall a.
(Eq a, Num a) =>
(CInt -> Bool) -> Socket -> String -> IO a -> IO a
throwSocketErrorWaitReadBut CInt -> Bool
exempt Socket
s String
name IO a
io = Socket -> (CInt -> IO a) -> IO a
forall r. Socket -> (CInt -> IO r) -> IO r
withFdSocket Socket
s ((CInt -> IO a) -> IO a) -> (CInt -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \CInt
fd ->
    (CInt -> Bool) -> String -> IO () -> IO a -> IO a
forall a b.
(Eq a, Num a) =>
(CInt -> Bool) -> String -> IO b -> IO a -> IO a
throwSocketErrorIfMinus1RetryMayBlockBut CInt -> Bool
exempt String
name
      (Fd -> IO ()
threadWaitRead (Fd -> IO ()) -> Fd -> IO ()
forall a b. (a -> b) -> a -> b
$ CInt -> Fd
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
fd) IO a
io
throwSocketErrorWaitWrite :: (Eq a, Num a) => Socket -> String -> IO a -> IO a
throwSocketErrorWaitWrite :: forall a. (Eq a, Num a) => Socket -> String -> IO a -> IO a
throwSocketErrorWaitWrite Socket
s String
name IO a
io = Socket -> (CInt -> IO a) -> IO a
forall r. Socket -> (CInt -> IO r) -> IO r
withFdSocket Socket
s ((CInt -> IO a) -> IO a) -> (CInt -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \CInt
fd ->
    String -> IO () -> IO a -> IO a
forall a b. (Eq a, Num a) => String -> IO b -> IO a -> IO a
throwSocketErrorIfMinus1RetryMayBlock String
name
      (Fd -> IO ()
threadWaitWrite (Fd -> IO ()) -> Fd -> IO ()
forall a b. (a -> b) -> a -> b
$ CInt -> Fd
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
fd) IO a
io
{-# INLINE withSocketsDo #-}
withSocketsDo :: IO a -> IO a
#if defined(mingw32_HOST_OS)
withSocketsDo act = evaluate withSocketsInit >> act
{-# NOINLINE withSocketsInit #-}
withSocketsInit :: ()
withSocketsInit = unsafePerformIO $ do
    x <- initWinSock
    when (x /= 0) $ ioError $
      userError "Network.Socket.Internal.withSocketsDo: Failed to initialise WinSock"
foreign import ccall unsafe "initWinSock" initWinSock :: IO Int
#else
withSocketsDo :: forall a. IO a -> IO a
withSocketsDo IO a
x = IO a
x
#endif