packages feed

quic-0.3.20: Network/QUIC/Client/WatchDog.hs

{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE InterruptibleFFI #-}

module Network.QUIC.Client.WatchDog (
    watchDog,
    watchDogWith,
    watchSocket,
) where

import Control.Concurrent
import qualified Control.Exception as E
import Foreign.C.Types

import Network.QUIC.Imports

-- | Running the action on every change of the network the OS reports,
--   until the OS cannot report them.
watchDog :: IO () -> IO ()
watchDog = watchDogWith c_open_socket c_watch_socket c_close_socket

-- | 'watchDog' with the socket calls given.  The watch returns 0 for an
--   event, -1 to be tried again and anything else to give up.  A socket
--   that could not be opened is never watched: a watch on it fails at
--   once, and trying it again spun.
watchDogWith
    :: IO CInt -> (CInt -> IO CInt) -> (CInt -> IO CInt) -> IO () -> IO ()
watchDogWith open watch clse action = E.bracket open release $ \s ->
    when (s >= 0) $ loop s
  where
    release s = when (s >= 0) $ void $ clse s
    loop s = do
        ret <- watch s
        case ret of
            0 -> do
                action
                -- prevent calling "migrate" frequently
                threadDelay 100000
                loop s
            -1 -> loop s
            _ -> return ()

-- | One watch on the socket, as 'watchDog' does.
watchSocket :: CInt -> IO CInt
watchSocket = c_watch_socket

foreign import ccall unsafe "open_socket"
    c_open_socket :: IO CInt

foreign import ccall interruptible "watch_socket"
    c_watch_socket :: CInt -> IO CInt

foreign import ccall unsafe "close_socket"
    c_close_socket :: CInt -> IO CInt