{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE CPP #-}
module Network.DNS.FFI where
import Control.Concurrent.MVar
import Control.Monad (unless)
import Control.Exception (bracket)
import Foreign.C
import Foreign.Marshal.Alloc
import Foreign.Ptr
import System.IO.Unsafe (unsafePerformIO)
#if !defined(USE_RES_NQUERY)
# error USE_RES_NQUERY not defined
#endif
{-# INLINE resIsReentrant #-}
resIsReentrant :: Bool
#if USE_RES_NQUERY
resIsReentrant :: Bool
resIsReentrant = Bool
True
#else
resIsReentrant = False
#endif
#if !defined(SIZEOF_RES_STATE)
# error SIZEOF_RES_STATE not defined
#endif
#if USE_RES_NQUERY && (SIZEOF_RES_STATE <= 0)
# error broken invariant
#endif
{-# INLINE sizeOfResState #-}
sizeOfResState :: CSize
sizeOfResState :: CSize
sizeOfResState = SIZEOF_RES_STATE
data CResState
{-# NOINLINE resolvLock #-}
resolvLock :: MVar ()
resolvLock :: MVar ()
resolvLock = IO (MVar ()) -> MVar ()
forall a. IO a -> a
unsafePerformIO (IO (MVar ()) -> MVar ()) -> IO (MVar ()) -> MVar ()
forall a b. (a -> b) -> a -> b
$ () -> IO (MVar ())
forall a. a -> IO (MVar a)
newMVar ()
withCResState :: (Ptr CResState -> IO a) -> IO a
withCResState :: forall a. (Ptr CResState -> IO a) -> IO a
withCResState Ptr CResState -> IO a
act
| Bool
resIsReentrant = Int -> (Ptr CResState -> IO a) -> IO a
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
sizeOfResState) ((Ptr CResState -> IO a) -> IO a)
-> (Ptr CResState -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr CResState
ptr -> do
Ptr CResState
_ <- Ptr CResState -> CInt -> CSize -> IO (Ptr CResState)
forall a. Ptr a -> CInt -> CSize -> IO (Ptr a)
c_memset Ptr CResState
ptr CInt
0 CSize
sizeOfResState
Ptr CResState -> IO a
act Ptr CResState
ptr
| Bool
otherwise = MVar () -> (() -> IO a) -> IO a
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar MVar ()
resolvLock ((() -> IO a) -> IO a) -> (() -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \() -> Ptr CResState -> IO a
act Ptr CResState
forall a. Ptr a
nullPtr
withCResInit :: Ptr CResState -> IO a -> IO a
withCResInit :: forall a. Ptr CResState -> IO a -> IO a
withCResInit Ptr CResState
stptr IO a
act = IO () -> (() -> IO ()) -> (() -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket IO ()
initialize () -> IO ()
forall {p}. p -> IO ()
finalize ((() -> IO a) -> IO a) -> (() -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ IO a -> () -> IO a
forall a b. a -> b -> a
const IO a
act
where
initialize :: IO ()
initialize = do
CInt
rc1 <- Ptr CResState -> IO CInt
c_res_opt_set_use_dnssec Ptr CResState
stptr
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (CInt
rc1 CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
0) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"res_init(3) failed"
IO ()
resetErrno
finalize :: p -> IO ()
finalize p
_ = Ptr CResState -> IO ()
c_res_close Ptr CResState
stptr
foreign import capi unsafe "string.h memset" c_memset :: Ptr a -> CInt -> CSize -> IO (Ptr a)
foreign import capi safe "hs_resolv.h hs_res_query" c_res_query :: Ptr CResState -> CString -> CInt -> CInt -> Ptr CChar -> CInt -> IO CInt
foreign import capi safe "hs_resolv.h hs_res_send" c_res_send :: Ptr CResState -> Ptr CChar -> CInt -> Ptr CChar -> CInt -> IO CInt
foreign import capi safe "hs_resolv.h res_opt_set_use_dnssec" c_res_opt_set_use_dnssec :: Ptr CResState -> IO CInt
foreign import capi safe "hs_resolv.h hs_res_mkquery" c_res_mkquery :: Ptr CResState -> CString -> CInt -> CInt -> Ptr CChar -> CInt -> IO CInt
foreign import capi safe "hs_resolv.h hs_res_close" c_res_close :: Ptr CResState -> IO ()
foreign import capi unsafe "hs_resolv.h hs_get_h_errno" c_get_h_errno :: Ptr CResState -> IO CInt