{-# 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
, NullSockAddr (..)
, 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