content: module Network.DNS.Types.Resolver where
  
  import Network.Socket (AddrInfo(..), PortNumber, HostName)
  
  import Network.DNS.Imports
  import Network.DNS.Memo
  import Network.DNS.Types.Internal
  
  ----------------------------------------------------------------
  
  -- | The type to specify a cache server.
  data FileOrNumericHost = RCFilePath FilePath -- ^ A path for \"resolv.conf\"
                                               -- where one or more IP addresses
                                               -- of DNS servers should be found
                                               -- on Unix.
                                               -- Default DNS servers are
                                               -- automatically detected
                                               -- on Windows regardless of
                                               -- the value of the file name.
                         | RCHostName HostName -- ^ A numeric IP address. /Warning/: host names are invalid.
                         | RCHostNames [HostName] -- ^ Numeric IP addresses. /Warning/: host names are invalid.
                         | RCHostPort HostName PortNumber -- ^ A numeric IP address and port number. /Warning/: host names are invalid.
                         deriving Show
  
  ----------------------------------------------------------------
  
  -- | Cache configuration for responses.
  data CacheConf = CacheConf {
      -- | If RR's TTL is higher than this value, this value is used instead.
      maximumTTL  :: TTL
      -- | Cache pruning interval in seconds.
    , pruningDelay  :: Int
    } deriving Show
  
  -- | Default cache configuration.
  --
  -- >>> defaultCacheConf
  -- CacheConf {maximumTTL = 300, pruningDelay = 10}
  defaultCacheConf :: CacheConf
  defaultCacheConf = CacheConf 300 10
  
  ----------------------------------------------------------------
  
  -- | Type for resolver configuration.
  --  Use 'defaultResolvConf' to create a new value.
  --
  --  An example to use Google's public DNS cache instead of resolv.conf:
  --
  --  >>> let conf = defaultResolvConf { resolvInfo = RCHostName "8.8.8.8" }
  --
  --  An example to use multiple Google's public DNS cache concurrently:
  --
  --  >>> let conf = defaultResolvConf { resolvInfo = RCHostNames ["8.8.8.8","8.8.4.4"], resolvConcurrent = True }
  --
  --  An example to disable EDNS:
  --
  --  >>> let conf = defaultResolvConf { resolvQueryControls = ednsEnabled FlagClear }
  --
  --  An example to enable query result caching:
  --
  --  >>> let conf = defaultResolvConf { resolvCache = Just defaultCacheConf }
  --
  -- An example to disable requesting recursive service.
  --
  --  >>> let conf = defaultResolvConf { resolvQueryControls = rdFlag FlagClear }
  --
  -- An example to set the AD bit in all queries by default.
  --
  --  >>> let conf = defaultResolvConf { resolvQueryControls = adFlag FlagSet }
  --
  -- An example to set the both the AD and CD bits in all queries by default.
  --
  --  >>> let conf = defaultResolvConf { resolvQueryControls = adFlag FlagSet <> cdFlag FlagSet }
  --
  -- An example with an EDNS buffer size of 1216 bytes, which is more robust with
  -- IPv6, and the DO bit set to request DNSSEC responses.
  --
  --  >>> let conf = defaultResolvConf { resolvQueryControls = ednsSetUdpSize (Just 1216) <> doFlag FlagSet }
  --
  data ResolvConf = ResolvConf {
     -- | Server information.
      resolvInfo       :: FileOrNumericHost
     -- | Timeout in micro seconds.
    , resolvTimeout    :: Int
     -- | The number of retries including the first try.
    , resolvRetry      :: Int
     -- | Concurrent queries if multiple DNS servers are specified.
    , resolvConcurrent :: Bool
     -- | Cache configuration.
    , resolvCache      :: Maybe CacheConf
     -- | Overrides for the default flags used for queries via resolvers that use
     -- this configuration.
    , resolvQueryControls :: QueryControls
  } deriving Show
  
  -- | Return a default 'ResolvConf':
  --
  -- * 'resolvInfo' is 'RCFilePath' \"\/etc\/resolv.conf\".
  -- * 'resolvTimeout' is 3,000,000 micro seconds.
  -- * 'resolvRetry' is 3.
  -- * 'resolvConcurrent' is False.
  -- * 'resolvCache' is Nothing.
  -- * 'resolvQueryControls' is an empty set of overrides.
  defaultResolvConf :: ResolvConf
  defaultResolvConf = ResolvConf {
      resolvInfo       = RCFilePath "/etc/resolv.conf"
    , resolvTimeout    = 3 * 1000 * 1000
    , resolvRetry      = 3
    , resolvConcurrent = False
    , resolvCache      = Nothing
    , resolvQueryControls = mempty
  }
  
  ----------------------------------------------------------------
  
  -- | Intermediate abstract data type for resolvers.
  --   IP address information of DNS servers is generated
  --   according to 'resolvInfo' internally.
  --   This value can be safely reused for 'withResolver'.
  --
  --   The naming is confusing for historical reasons.
  data ResolvSeed = ResolvSeed {
      resolvconf  :: ResolvConf
    , nameservers :: NonEmpty AddrInfo
  }
  
  ----------------------------------------------------------------
  
  -- | Abstract data type of DNS Resolver.
  --   This includes newly seeded identifier generators for all
  --   specified DNS servers and a cache database.
  data Resolver = Resolver {
      resolvseed :: ResolvSeed
    , genIds     :: NonEmpty (IO Word16)
    , cache      :: Maybe Cache
  }
  