{-# LANGUAGE CPP                 #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE NamedFieldPuns      #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- | IP subscription worker implentation.
module Ouroboros.Network.Subscription.Ip
  ( SubscriptionParams (..)
  , IPSubscriptionParams
  , ipSubscriptionWorker
  , subscriptionWorker
  , IPSubscriptionTarget (..)
  , ipSubscriptionTarget
    --  * Traces
  , SubscriptionTrace (..)
  , ErrorPolicyTrace (..)
  , WithIPList (..)
    -- * 'PeerState' STM transactions
  , BeforeConnect
  , runBeforeConnect
  , beforeConnectTx
  , completeApplicationTx
  , socketStateChangeTx
  , mainTx
    -- * Utilitity functions
  , selectSockAddr
  ) where


{- The parallel connection attemps implemented in this module is inspired by
 - RFC8305, https://tools.ietf.org/html/rfc8305 .
 -}

import           Control.Monad.Class.MonadSTM.Strict
import           Control.Monad.Class.MonadThrow
import           Control.Monad.Class.MonadTime
import           Control.Tracer
import           Data.Void (Void)
import qualified Network.Socket as Socket
import           Text.Printf

import           Ouroboros.Network.ErrorPolicy
import           Ouroboros.Network.Snocket (Snocket)
import           Ouroboros.Network.Socket
import           Ouroboros.Network.Subscription.PeerState
import           Ouroboros.Network.Subscription.Subscriber
import           Ouroboros.Network.Subscription.Worker


data IPSubscriptionTarget = IPSubscriptionTarget {
    -- | List of destinations to possibly connect to
      IPSubscriptionTarget -> [SockAddr]
ispIps     :: ![Socket.SockAddr]
    -- | Number of parallel connections to keep actice.
    , IPSubscriptionTarget -> Int
ispValency :: !Int
    } deriving (IPSubscriptionTarget -> IPSubscriptionTarget -> Bool
(IPSubscriptionTarget -> IPSubscriptionTarget -> Bool)
-> (IPSubscriptionTarget -> IPSubscriptionTarget -> Bool)
-> Eq IPSubscriptionTarget
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: IPSubscriptionTarget -> IPSubscriptionTarget -> Bool
$c/= :: IPSubscriptionTarget -> IPSubscriptionTarget -> Bool
== :: IPSubscriptionTarget -> IPSubscriptionTarget -> Bool
$c== :: IPSubscriptionTarget -> IPSubscriptionTarget -> Bool
Eq, Int -> IPSubscriptionTarget -> ShowS
[IPSubscriptionTarget] -> ShowS
IPSubscriptionTarget -> String
(Int -> IPSubscriptionTarget -> ShowS)
-> (IPSubscriptionTarget -> String)
-> ([IPSubscriptionTarget] -> ShowS)
-> Show IPSubscriptionTarget
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IPSubscriptionTarget] -> ShowS
$cshowList :: [IPSubscriptionTarget] -> ShowS
show :: IPSubscriptionTarget -> String
$cshow :: IPSubscriptionTarget -> String
showsPrec :: Int -> IPSubscriptionTarget -> ShowS
$cshowsPrec :: Int -> IPSubscriptionTarget -> ShowS
Show)


-- | 'ipSubscriptionWorker' and 'dnsSubscriptionWorker' parameters
--
data SubscriptionParams a target = SubscriptionParams
  { SubscriptionParams a target -> LocalAddresses SockAddr
spLocalAddresses         :: LocalAddresses Socket.SockAddr
  , SubscriptionParams a target -> SockAddr -> Maybe DiffTime
spConnectionAttemptDelay :: Socket.SockAddr -> Maybe DiffTime
    -- ^ should return expected delay for the given address
  , SubscriptionParams a target -> ErrorPolicies
spErrorPolicies          :: ErrorPolicies
  , SubscriptionParams a target -> target
spSubscriptionTarget     :: target
  }

type IPSubscriptionParams a = SubscriptionParams a IPSubscriptionTarget

-- | Spawns a subscription worker which will attempt to keep the specified
-- number of connections (Valency) active towards the list of IP addresses
-- given in IPSubscriptionTarget.
--
ipSubscriptionWorker
    :: forall a.
       Snocket IO Socket.Socket Socket.SockAddr
    -> Tracer IO (WithIPList (SubscriptionTrace Socket.SockAddr))
    -> Tracer IO (WithAddr Socket.SockAddr ErrorPolicyTrace)
    -> NetworkMutableState Socket.SockAddr
    -> IPSubscriptionParams a
    -> (Socket.Socket -> IO a)
    -> IO Void
ipSubscriptionWorker :: Snocket IO Socket SockAddr
-> Tracer IO (WithIPList (SubscriptionTrace SockAddr))
-> Tracer IO (WithAddr SockAddr ErrorPolicyTrace)
-> NetworkMutableState SockAddr
-> IPSubscriptionParams a
-> (Socket -> IO a)
-> IO Void
ipSubscriptionWorker Snocket IO Socket SockAddr
snocket Tracer IO (WithIPList (SubscriptionTrace SockAddr))
subscriptionTracer Tracer IO (WithAddr SockAddr ErrorPolicyTrace)
errorPolicyTracer
                     networkState :: NetworkMutableState SockAddr
networkState@NetworkMutableState { StrictTVar IO (PeerStates IO SockAddr)
nmsPeerStates :: forall addr.
NetworkMutableState addr -> StrictTVar IO (PeerStates IO addr)
nmsPeerStates :: StrictTVar IO (PeerStates IO SockAddr)
nmsPeerStates }
                     SubscriptionParams { LocalAddresses SockAddr
spLocalAddresses :: LocalAddresses SockAddr
spLocalAddresses :: forall a target.
SubscriptionParams a target -> LocalAddresses SockAddr
spLocalAddresses
                                        , SockAddr -> Maybe DiffTime
spConnectionAttemptDelay :: SockAddr -> Maybe DiffTime
spConnectionAttemptDelay :: forall a target.
SubscriptionParams a target -> SockAddr -> Maybe DiffTime
spConnectionAttemptDelay
                                        , IPSubscriptionTarget
spSubscriptionTarget :: IPSubscriptionTarget
spSubscriptionTarget :: forall a target. SubscriptionParams a target -> target
spSubscriptionTarget
                                        , ErrorPolicies
spErrorPolicies :: ErrorPolicies
spErrorPolicies :: forall a target. SubscriptionParams a target -> ErrorPolicies
spErrorPolicies
                                        }
                     Socket -> IO a
k =
    Snocket IO Socket SockAddr
-> Tracer IO (SubscriptionTrace SockAddr)
-> Tracer IO (WithAddr SockAddr ErrorPolicyTrace)
-> NetworkMutableState SockAddr
-> WorkerParams IO LocalAddresses SockAddr
-> ErrorPolicies
-> Main IO (PeerStates IO SockAddr) Void
-> (Socket -> IO a)
-> IO Void
forall x a.
Snocket IO Socket SockAddr
-> Tracer IO (SubscriptionTrace SockAddr)
-> Tracer IO (WithAddr SockAddr ErrorPolicyTrace)
-> NetworkMutableState SockAddr
-> WorkerParams IO LocalAddresses SockAddr
-> ErrorPolicies
-> Main IO (PeerStates IO SockAddr) x
-> (Socket -> IO a)
-> IO x
subscriptionWorker Snocket IO Socket SockAddr
snocket
                       Tracer IO (SubscriptionTrace SockAddr)
subscriptionTracer'
                       Tracer IO (WithAddr SockAddr ErrorPolicyTrace)
errorPolicyTracer
                       NetworkMutableState SockAddr
networkState
                       WorkerParams IO LocalAddresses SockAddr
workerParams
                       ErrorPolicies
spErrorPolicies
                       Main IO (PeerStates IO SockAddr) Void
forall (m :: * -> *) addr.
(MonadThrow (STM m), MonadSTM m) =>
Main m (PeerStates m addr) Void
mainTx
                       Socket -> IO a
k
  where
    workerParams :: WorkerParams IO LocalAddresses SockAddr
workerParams = WorkerParams :: forall (m :: * -> *) (localAddrs :: * -> *) addr.
localAddrs addr
-> (addr -> localAddrs addr -> Maybe addr)
-> (addr -> Maybe DiffTime)
-> m (SubscriptionTarget m addr)
-> Int
-> WorkerParams m localAddrs addr
WorkerParams {
        wpLocalAddresses :: LocalAddresses SockAddr
wpLocalAddresses         = LocalAddresses SockAddr
spLocalAddresses,
        wpConnectionAttemptDelay :: SockAddr -> Maybe DiffTime
wpConnectionAttemptDelay = SockAddr -> Maybe DiffTime
spConnectionAttemptDelay,
        wpSubscriptionTarget :: IO (SubscriptionTarget IO SockAddr)
wpSubscriptionTarget     =
          SubscriptionTarget IO SockAddr
-> IO (SubscriptionTarget IO SockAddr)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SubscriptionTarget IO SockAddr
 -> IO (SubscriptionTarget IO SockAddr))
-> SubscriptionTarget IO SockAddr
-> IO (SubscriptionTarget IO SockAddr)
forall a b. (a -> b) -> a -> b
$ Tracer IO (SubscriptionTrace SockAddr)
-> StrictTVar IO (PeerStates IO SockAddr)
-> [SockAddr]
-> SubscriptionTarget IO SockAddr
forall (m :: * -> *) addr.
(MonadSTM m, MonadTime m, Ord addr) =>
Tracer m (SubscriptionTrace addr)
-> StrictTVar m (PeerStates m addr)
-> [addr]
-> SubscriptionTarget m addr
ipSubscriptionTarget Tracer IO (SubscriptionTrace SockAddr)
subscriptionTracer' StrictTVar IO (PeerStates IO SockAddr)
nmsPeerStates
                                      (IPSubscriptionTarget -> [SockAddr]
ispIps IPSubscriptionTarget
spSubscriptionTarget),
        wpValency :: Int
wpValency                = IPSubscriptionTarget -> Int
ispValency IPSubscriptionTarget
spSubscriptionTarget,
        wpSelectAddress :: SockAddr -> LocalAddresses SockAddr -> Maybe SockAddr
wpSelectAddress          = SockAddr -> LocalAddresses SockAddr -> Maybe SockAddr
selectSockAddr
      }

    subscriptionTracer' :: Tracer IO (SubscriptionTrace SockAddr)
subscriptionTracer' = (LocalAddresses SockAddr
-> [SockAddr]
-> SubscriptionTrace SockAddr
-> WithIPList (SubscriptionTrace SockAddr)
forall a.
LocalAddresses SockAddr -> [SockAddr] -> a -> WithIPList a
WithIPList LocalAddresses SockAddr
spLocalAddresses (IPSubscriptionTarget -> [SockAddr]
ispIps IPSubscriptionTarget
spSubscriptionTarget)
              (SubscriptionTrace SockAddr
 -> WithIPList (SubscriptionTrace SockAddr))
-> Tracer IO (WithIPList (SubscriptionTrace SockAddr))
-> Tracer IO (SubscriptionTrace SockAddr)
forall (f :: * -> *) a b. Contravariant f => (a -> b) -> f b -> f a
`contramap` Tracer IO (WithIPList (SubscriptionTrace SockAddr))
subscriptionTracer)

selectSockAddr :: Socket.SockAddr
               -> LocalAddresses Socket.SockAddr
               -> Maybe Socket.SockAddr
selectSockAddr :: SockAddr -> LocalAddresses SockAddr -> Maybe SockAddr
selectSockAddr Socket.SockAddrInet{}  (LocalAddresses (Just SockAddr
localAddr) Maybe SockAddr
_ Maybe SockAddr
_ ) = SockAddr -> Maybe SockAddr
forall a. a -> Maybe a
Just SockAddr
localAddr
selectSockAddr Socket.SockAddrInet6{} (LocalAddresses Maybe SockAddr
_ (Just SockAddr
localAddr) Maybe SockAddr
_ ) = SockAddr -> Maybe SockAddr
forall a. a -> Maybe a
Just SockAddr
localAddr
selectSockAddr Socket.SockAddrUnix{}  (LocalAddresses Maybe SockAddr
_ Maybe SockAddr
_ (Just SockAddr
localAddr) ) = SockAddr -> Maybe SockAddr
forall a. a -> Maybe a
Just SockAddr
localAddr
selectSockAddr SockAddr
_ LocalAddresses SockAddr
_ = Maybe SockAddr
forall a. Maybe a
Nothing


ipSubscriptionTarget :: forall m addr.
                        ( MonadSTM  m
                        , MonadTime m
                        , Ord addr
                        )
                     => Tracer m (SubscriptionTrace addr)
                     -> StrictTVar m (PeerStates m addr)
                     -> [addr]
                     -> SubscriptionTarget m addr
ipSubscriptionTarget :: Tracer m (SubscriptionTrace addr)
-> StrictTVar m (PeerStates m addr)
-> [addr]
-> SubscriptionTarget m addr
ipSubscriptionTarget Tracer m (SubscriptionTrace addr)
tr StrictTVar m (PeerStates m addr)
peerStatesVar [addr]
ips = [addr] -> SubscriptionTarget m addr
go [addr]
ips
  where
    go :: [addr]
       -> SubscriptionTarget m addr
    go :: [addr] -> SubscriptionTarget m addr
go [] = m (Maybe (addr, SubscriptionTarget m addr))
-> SubscriptionTarget m addr
forall (m :: * -> *) target.
m (Maybe (target, SubscriptionTarget m target))
-> SubscriptionTarget m target
SubscriptionTarget (m (Maybe (addr, SubscriptionTarget m addr))
 -> SubscriptionTarget m addr)
-> m (Maybe (addr, SubscriptionTarget m addr))
-> SubscriptionTarget m addr
forall a b. (a -> b) -> a -> b
$ Maybe (addr, SubscriptionTarget m addr)
-> m (Maybe (addr, SubscriptionTarget m addr))
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (addr, SubscriptionTarget m addr)
forall a. Maybe a
Nothing
    go (addr
a : [addr]
as) = m (Maybe (addr, SubscriptionTarget m addr))
-> SubscriptionTarget m addr
forall (m :: * -> *) target.
m (Maybe (target, SubscriptionTarget m target))
-> SubscriptionTarget m target
SubscriptionTarget (m (Maybe (addr, SubscriptionTarget m addr))
 -> SubscriptionTarget m addr)
-> m (Maybe (addr, SubscriptionTarget m addr))
-> SubscriptionTarget m addr
forall a b. (a -> b) -> a -> b
$ do
      Bool
b <- StrictTVar m (PeerStates m addr)
-> BeforeConnect m (PeerStates m addr) addr -> addr -> m Bool
forall (m :: * -> *) s addr.
(MonadSTM m, MonadTime m) =>
StrictTVar m s -> BeforeConnect m s addr -> addr -> m Bool
runBeforeConnect StrictTVar m (PeerStates m addr)
peerStatesVar BeforeConnect m (PeerStates m addr) addr
forall (m :: * -> *) addr.
(MonadSTM m, Ord addr) =>
BeforeConnect m (PeerStates m addr) addr
beforeConnectTx addr
a
      if Bool
b
        then do
          Tracer m (SubscriptionTrace addr) -> SubscriptionTrace addr -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (SubscriptionTrace addr)
tr (SubscriptionTrace addr -> m ()) -> SubscriptionTrace addr -> m ()
forall a b. (a -> b) -> a -> b
$ addr -> SubscriptionTrace addr
forall addr. addr -> SubscriptionTrace addr
SubscriptionTraceTryConnectToPeer addr
a
          Maybe (addr, SubscriptionTarget m addr)
-> m (Maybe (addr, SubscriptionTarget m addr))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (addr, SubscriptionTarget m addr)
 -> m (Maybe (addr, SubscriptionTarget m addr)))
-> Maybe (addr, SubscriptionTarget m addr)
-> m (Maybe (addr, SubscriptionTarget m addr))
forall a b. (a -> b) -> a -> b
$ (addr, SubscriptionTarget m addr)
-> Maybe (addr, SubscriptionTarget m addr)
forall a. a -> Maybe a
Just (addr
a, [addr] -> SubscriptionTarget m addr
go [addr]
as)
        else do
          Tracer m (SubscriptionTrace addr) -> SubscriptionTrace addr -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (SubscriptionTrace addr)
tr (SubscriptionTrace addr -> m ()) -> SubscriptionTrace addr -> m ()
forall a b. (a -> b) -> a -> b
$ addr -> SubscriptionTrace addr
forall addr. addr -> SubscriptionTrace addr
SubscriptionTraceSkippingPeer addr
a
          SubscriptionTarget m addr
-> m (Maybe (addr, SubscriptionTarget m addr))
forall (m :: * -> *) target.
SubscriptionTarget m target
-> m (Maybe (target, SubscriptionTarget m target))
getSubscriptionTarget (SubscriptionTarget m addr
 -> m (Maybe (addr, SubscriptionTarget m addr)))
-> SubscriptionTarget m addr
-> m (Maybe (addr, SubscriptionTarget m addr))
forall a b. (a -> b) -> a -> b
$ [addr] -> SubscriptionTarget m addr
go [addr]
as


-- when creating a new socket: register consumer thread
-- when tearing down a socket: unregister consumer thread
socketStateChangeTx
    :: Ord addr
    => SocketStateChange IO
        (PeerStates IO addr)
        addr

socketStateChangeTx :: SocketStateChange IO (PeerStates IO addr) addr
socketStateChangeTx (CreatedSocket addr
addr Async IO ()
thread) PeerStates IO addr
ps =
  PeerStates IO addr -> STM (PeerStates IO addr)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (addr -> Async IO () -> PeerStates IO addr -> PeerStates IO addr
forall (m :: * -> *) addr.
(Ord addr, Ord (Async m ())) =>
addr -> Async m () -> PeerStates m addr -> PeerStates m addr
registerConsumer addr
addr Async IO ()
thread PeerStates IO addr
ps)

socketStateChangeTx ClosedSocket{} ps :: PeerStates IO addr
ps@ThrowException{} =
  PeerStates IO addr -> STM (PeerStates IO addr)
forall (f :: * -> *) a. Applicative f => a -> f a
pure PeerStates IO addr
ps

socketStateChangeTx (ClosedSocket addr
addr Async IO ()
thread) PeerStates IO addr
ps =
  PeerStates IO addr -> STM (PeerStates IO addr)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PeerStates IO addr -> STM (PeerStates IO addr))
-> PeerStates IO addr -> STM (PeerStates IO addr)
forall a b. (a -> b) -> a -> b
$ addr -> Async IO () -> PeerStates IO addr -> PeerStates IO addr
forall (m :: * -> *) addr.
(Ord addr, Ord (Async m ())) =>
addr -> Async m () -> PeerStates m addr -> PeerStates m addr
unregisterConsumer addr
addr Async IO ()
thread PeerStates IO addr
ps


-- | Main callback.  It throws an exception when the state becomes
-- 'ThrowException'.  This exception is thrown from the main thread.
--
mainTx :: ( MonadThrow (STM m)
          , MonadSTM m
          )
       => Main m (PeerStates m addr) Void
mainTx :: Main m (PeerStates m addr) Void
mainTx (ThrowException e
e) = e -> STM m Void
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwIO e
e
mainTx PeerStates{}       = STM m Void
forall (m :: * -> *) a. MonadSTM m => STM m a
retry


-- | Like 'worker' but in 'IO'; It provides address selection function,
-- 'SocketStateChange' and 'CompleteApplication' callbacks.  The 'Main'
-- callback is left as it's useful for testing purposes.
--
subscriptionWorker
    :: Snocket IO Socket.Socket Socket.SockAddr
    -> Tracer IO (SubscriptionTrace Socket.SockAddr)
    -> Tracer IO (WithAddr Socket.SockAddr ErrorPolicyTrace)
    -> NetworkMutableState Socket.SockAddr
    -> WorkerParams IO LocalAddresses Socket.SockAddr
    -> ErrorPolicies
    -> Main IO (PeerStates IO Socket.SockAddr) x
    -- ^ main callback
    -> (Socket.Socket -> IO a)
    -- ^ application to run on each connection
    -> IO x
subscriptionWorker :: Snocket IO Socket SockAddr
-> Tracer IO (SubscriptionTrace SockAddr)
-> Tracer IO (WithAddr SockAddr ErrorPolicyTrace)
-> NetworkMutableState SockAddr
-> WorkerParams IO LocalAddresses SockAddr
-> ErrorPolicies
-> Main IO (PeerStates IO SockAddr) x
-> (Socket -> IO a)
-> IO x
subscriptionWorker Snocket IO Socket SockAddr
snocket
                   Tracer IO (SubscriptionTrace SockAddr)
tracer
                   Tracer IO (WithAddr SockAddr ErrorPolicyTrace)
errorPolicyTracer
                   NetworkMutableState { ConnectionTable IO SockAddr
nmsConnectionTable :: forall addr. NetworkMutableState addr -> ConnectionTable IO addr
nmsConnectionTable :: ConnectionTable IO SockAddr
nmsConnectionTable, StrictTVar IO (PeerStates IO SockAddr)
nmsPeerStates :: StrictTVar IO (PeerStates IO SockAddr)
nmsPeerStates :: forall addr.
NetworkMutableState addr -> StrictTVar IO (PeerStates IO addr)
nmsPeerStates }
                   WorkerParams IO LocalAddresses SockAddr
workerParams
                   ErrorPolicies
errorPolicies
                   Main IO (PeerStates IO SockAddr) x
main Socket -> IO a
k =
    Tracer IO (SubscriptionTrace SockAddr)
-> Tracer IO (WithAddr SockAddr ErrorPolicyTrace)
-> ConnectionTable IO SockAddr
-> StrictTVar IO (PeerStates IO SockAddr)
-> Snocket IO Socket SockAddr
-> WorkerCallbacks IO (PeerStates IO SockAddr) SockAddr a x
-> WorkerParams IO LocalAddresses SockAddr
-> (Socket -> IO a)
-> IO x
forall s sock (localAddrs :: * -> *) addr a x.
Ord addr =>
Tracer IO (SubscriptionTrace addr)
-> Tracer IO (WithAddr addr ErrorPolicyTrace)
-> ConnectionTable IO addr
-> StateVar IO s
-> Snocket IO sock addr
-> WorkerCallbacks IO s addr a x
-> WorkerParams IO localAddrs addr
-> (sock -> IO a)
-> IO x
worker Tracer IO (SubscriptionTrace SockAddr)
tracer
           Tracer IO (WithAddr SockAddr ErrorPolicyTrace)
errorPolicyTracer
           ConnectionTable IO SockAddr
nmsConnectionTable
           StrictTVar IO (PeerStates IO SockAddr)
nmsPeerStates
           Snocket IO Socket SockAddr
snocket
           WorkerCallbacks :: forall (m :: * -> *) s addr a t.
SocketStateChange m s addr
-> CompleteApplication m s addr a
-> Main m s t
-> WorkerCallbacks m s addr a t
WorkerCallbacks
             { wcSocketStateChangeTx :: SocketStateChange IO (PeerStates IO SockAddr) SockAddr
wcSocketStateChangeTx   = SocketStateChange IO (PeerStates IO SockAddr) SockAddr
forall addr.
Ord addr =>
SocketStateChange IO (PeerStates IO addr) addr
socketStateChangeTx
             , wcCompleteApplicationTx :: CompleteApplication IO (PeerStates IO SockAddr) SockAddr a
wcCompleteApplicationTx = ErrorPolicies
-> CompleteApplication IO (PeerStates IO SockAddr) SockAddr a
forall (m :: * -> *) addr a.
(MonadAsync m, Ord addr, Ord (Async m ())) =>
ErrorPolicies -> CompleteApplication m (PeerStates m addr) addr a
completeApplicationTx ErrorPolicies
errorPolicies
             , wcMainTx :: Main IO (PeerStates IO SockAddr) x
wcMainTx                = Main IO (PeerStates IO SockAddr) x
main
             }
           WorkerParams IO LocalAddresses SockAddr
workerParams
           Socket -> IO a
k

data WithIPList a = WithIPList {
      WithIPList a -> LocalAddresses SockAddr
wilSrc   :: (LocalAddresses Socket.SockAddr)
    , WithIPList a -> [SockAddr]
wilDsts  :: [Socket.SockAddr]
    , WithIPList a -> a
wilEvent :: a
    }

instance (Show a) => Show (WithIPList a) where
    show :: WithIPList a -> String
show (WithIPList (LocalAddresses Maybe SockAddr
Nothing (Just SockAddr
ipv6) Maybe SockAddr
Nothing) [SockAddr]
wilDsts a
wilEvent) =
        String -> String -> String -> ShowS
forall r. PrintfType r => String -> r
printf String
"IPs: %s %s %s" (SockAddr -> String
forall a. Show a => a -> String
show SockAddr
ipv6) ([SockAddr] -> String
forall a. Show a => a -> String
show [SockAddr]
wilDsts) (a -> String
forall a. Show a => a -> String
show a
wilEvent)
    show (WithIPList (LocalAddresses (Just SockAddr
ipv4) Maybe SockAddr
Nothing Maybe SockAddr
Nothing) [SockAddr]
wilDsts a
wilEvent) =
        String -> String -> String -> ShowS
forall r. PrintfType r => String -> r
printf String
"IPs: %s %s %s" (SockAddr -> String
forall a. Show a => a -> String
show SockAddr
ipv4) ([SockAddr] -> String
forall a. Show a => a -> String
show [SockAddr]
wilDsts) (a -> String
forall a. Show a => a -> String
show a
wilEvent)
    show (WithIPList (LocalAddresses Maybe SockAddr
Nothing Maybe SockAddr
Nothing (Just SockAddr
unix)) [SockAddr]
wilDsts a
wilEvent) =
        String -> String -> String -> ShowS
forall r. PrintfType r => String -> r
printf String
"IPs: %s %s %s" (SockAddr -> String
forall a. Show a => a -> String
show SockAddr
unix) ([SockAddr] -> String
forall a. Show a => a -> String
show [SockAddr]
wilDsts) (a -> String
forall a. Show a => a -> String
show a
wilEvent)
    show (WithIPList (LocalAddresses (Just SockAddr
ipv4) (Just SockAddr
ipv6) Maybe SockAddr
Nothing) [SockAddr]
wilDsts a
wilEvent) =
        String -> String -> String -> String -> ShowS
forall r. PrintfType r => String -> r
printf  String
"IPs: %s %s %s %s" (SockAddr -> String
forall a. Show a => a -> String
show SockAddr
ipv4) (SockAddr -> String
forall a. Show a => a -> String
show SockAddr
ipv6)
                                   ([SockAddr] -> String
forall a. Show a => a -> String
show [SockAddr]
wilDsts) (a -> String
forall a. Show a => a -> String
show a
wilEvent)
    show WithIPList {LocalAddresses SockAddr
wilSrc :: LocalAddresses SockAddr
wilSrc :: forall a. WithIPList a -> LocalAddresses SockAddr
wilSrc, [SockAddr]
wilDsts :: [SockAddr]
wilDsts :: forall a. WithIPList a -> [SockAddr]
wilDsts, a
wilEvent :: a
wilEvent :: forall a. WithIPList a -> a
wilEvent} =
        String -> String -> String -> ShowS
forall r. PrintfType r => String -> r
printf String
"IPs: %s %s %s" (LocalAddresses SockAddr -> String
forall a. Show a => a -> String
show LocalAddresses SockAddr
wilSrc) ([SockAddr] -> String
forall a. Show a => a -> String
show [SockAddr]
wilDsts) (a -> String
forall a. Show a => a -> String
show a
wilEvent)