Add a "timeout" command-line argument.
authorMichael Orlitzky <michael@orlitzky.com>
Tue, 3 Sep 2013 15:19:15 +0000 (11:19 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Tue, 3 Sep 2013 15:19:15 +0000 (11:19 -0400)
doc/man1/haeredes.1
haeredes.cabal
src/CommandLine.hs
src/Main.hs
src/Timeout.hs [new file with mode: 0644]

index 569897e603c9af9a56bf82bb7ad685f27adc27e9..900b4c64e195bc044fc68c149b6b178dc3afb778 100644 (file)
@@ -100,6 +100,8 @@ probably just lead to false positives.
 .IP \fB\-\-server\fR,\ \fB-s\fR
 Use the given DNS server rather than the resolvers listed in
 /etc/resolv.conf. Either an IP address or a hostname will work.
+.IP \fB\-\-timeout\fR,\ \fB-t\fR
+The number of seconds to wait for an answer from DNS (default: 15).
 .SH EXAMPLES
 
 .IP \[bu] 2
index 631f5eba064c28df90b62e14641893c5d642eede..5b7969a4837855383d699ffeb26ea0e17c983f1d 100644 (file)
@@ -1,5 +1,5 @@
 name:           haeredes
-version:        0.1
+version:        0.2
 cabal-version:  >= 1.8
 author:         Michael Orlitzky
 maintainer:    Michael Orlitzky <michael@orlitzky.com>
@@ -104,6 +104,7 @@ executable haeredes
     CommandLine
     DNS
     ExitCodes
+    Timeout
 
   ghc-options:
     -Wall
index 2118f5911ec2c533128f5a5c41530348ca10c362..b94e378e516517e5c9d116fae5fe6979876b509e 100644 (file)
@@ -30,6 +30,8 @@ import System.Console.CmdArgs (
 import Paths_haeredes (version)
 import Data.Version (showVersion)
 
+import Timeout (Timeout(..))
+
 -- | Description of the 'NS' mode.
 ns_description :: String
 ns_description =
@@ -56,15 +58,24 @@ server_help =
   "IP address or hostname of server to query " ++
   "(will use resolv.conf if not specified)"
 
+-- | Help string for the --timeout flag.
+timeout_help :: String
+timeout_help =
+  "Query timeout, in seconds (default: " ++ defstr ++ ")"
+  where
+    defstr = show $ seconds (def :: Timeout)
+
 -- | The Args type represents the possible command-line options. The
 --   duplication here seems necessary; CmdArgs' magic requires us to
 --   define some things explicitly.
 data Args =
   NS { no_append_root :: Bool,
        server :: Maybe String,
+       timeout :: Timeout,
        delegates :: [String] } |
   MX { no_append_root :: Bool,
        server :: Maybe String,
+       timeout :: Timeout,
        delegates :: [String] }
   deriving (Data, Show, Typeable)
 
@@ -94,6 +105,11 @@ arg_spec =
                  &= typ "HOST"
                  &= help server_help,
 
+           timeout = def
+                   &= groupname "Common flags"
+                   &= typ "SECONDS"
+                   &= help timeout_help,
+
            delegates = def
                     &= args
                     &= typ "DELEGATES" }
@@ -111,6 +127,11 @@ arg_spec =
                  &= typ "IP"
                  &= help server_help,
 
+           timeout = def
+                   &= groupname "Common flags"
+                   &= typ "SECONDS"
+                   &= help timeout_help,
+
            delegates = def
                     &= args
                     &= typ "DELEGATES" }
index 6b276b7980b9b5687493f6b72ab46590d5fb9b9d..4e0da6b6dc0296e730025f5295219eeaae254fe1 100644 (file)
@@ -14,7 +14,7 @@ import Data.String.Utils (join)
 import Network.DNS (
   Domain,
   FileOrNumericHost(RCHostName),
-  ResolvConf(resolvInfo),
+  ResolvConf(resolvInfo, resolvTimeout),
   defaultResolvConf,
   makeResolvSeed,
   withResolver )
@@ -31,6 +31,7 @@ import DNS (
   normalize_case,
   resolve_address )
 import ExitCodes (exit_bad_server)
+import Timeout (Timeout(..))
 
 
 -- | Report results for this LookupResult. If there's a Nothing in the
@@ -83,18 +84,21 @@ main = do
   let nrml_domains   = map normalize_function raw_domains
   let nrml_delegates = map normalize_function raw_delegates
 
-  rc <- case (server cfg) of
-          Nothing -> return defaultResolvConf
-          Just s -> do
-            s' <- resolve_address s
-            case s' of
-              Nothing -> do
-                hPutStrLn stderr ("Bad DNS server or lookup error: " ++ s)
-                exitWith (ExitFailure exit_bad_server)
-              Just s'' ->
-                return $ defaultResolvConf { resolvInfo =
-                                               RCHostName (show s'') }
-
+  rc' <- case (server cfg) of
+           Nothing -> return defaultResolvConf
+           Just s -> do
+             s' <- resolve_address s
+             case s' of
+               Nothing -> do
+                 hPutStrLn stderr ("Bad DNS server or lookup error: " ++ s)
+                 exitWith (ExitFailure exit_bad_server)
+               Just s'' ->
+                 return $ defaultResolvConf { resolvInfo =
+                                                RCHostName (show s'') }
+
+  -- Set the timeout from the command line. The resolvTimeout field is
+  -- in microseconds, so we multiply by one million.
+  let rc = rc' { resolvTimeout = 1000 * 1000 * (seconds $ timeout cfg) }
   rs <- makeResolvSeed rc
 
   let lookup_function = case cfg of
diff --git a/src/Timeout.hs b/src/Timeout.hs
new file mode 100644 (file)
index 0000000..6f0f3d4
--- /dev/null
@@ -0,0 +1,18 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+-- | A newtype around the DNS query timeout, in seconds. Needed for
+--   the 'Default' instance.
+--
+module Timeout
+where
+
+import Data.Data (Data)
+import System.Console.CmdArgs.Default (Default(..))
+import Data.Typeable (Typeable)
+
+newtype Timeout =
+  Timeout { seconds :: Int }
+  deriving (Data, Show, Typeable)
+
+instance Default Timeout where
+  def = Timeout 15