shill: resolver: Use (even) smaller DNS timeout

Use the new glibc facility for sub-second timeouts, and choose
300 milliseconds for the timeout.  However, only do this by
default for Ethernet and WiFi networks, since VPN networks
in particular have trouble with this configuration (due to many
name servers and search domains, as well as the additional
latency inherent to such networks).  Also, increase the number
of attempts, so we still spend a reasonable amount of time
overall waiting for a DNS response.

Provide a means to change which technologies are setup in this
manner.

BUG=chromium-os:29124
TEST=Manual: Install connection manager, verify via strace that
gethostbyname now waits 300 ms, and retries 15 times per trial (*).
Ensure Chromium continues to work correctly under light loads.
Also, connect via Verizon and VPN and ensure DNS parameters
are back to the long timeout.
List manager properties and ensure it says "ethernet,wifi" for
ShortDNSTimeoutTechnologies and that this is saved out to the
profile.
New unit tests.
CQ-DEPENDS=Ib9ffc59bbfcd5bf3f57d146965c5a43a936348f8

*: Each trial consists of a nameserver / IP address pair, so
for example, if we have IPv6 connectivity and have two "server"
entries in resolv.conf, we first do 30 tries of IPv6 requests,
alternating between the two servers, then another 30 alternating
IPv4 requests between them.  This was tested by intentionally
making the DNS server unreachable and instrumenting the gethostbyname
request via strace.

Change-Id: Idd331b4a9fcf96d457ab9959537aefcb86328e12
Reviewed-on: https://gerrit.chromium.org/gerrit/26493
Commit-Ready: Paul Stewart <pstew@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/resolver.cc b/resolver.cc
index b0bc41c..7cbe6d1 100644
--- a/resolver.cc
+++ b/resolver.cc
@@ -24,6 +24,12 @@
 base::LazyInstance<Resolver> g_resolver = LAZY_INSTANCE_INITIALIZER;
 }  // namespace
 
+const char Resolver::kDefaultShortTimeoutTechnologies[] = "ethernet,wifi";
+const char Resolver::kDefaultTimeoutOptions[] =
+    "options single-request timeout:1 attempts:3";
+const char Resolver::kShortTimeoutOptions[] =
+    "options single-request timeout-ms:300 attempts:15";
+
 Resolver::Resolver() {}
 
 Resolver::~Resolver() {}
@@ -32,18 +38,20 @@
   return g_resolver.Pointer();
 }
 
-bool Resolver::SetDNSFromIPConfig(const IPConfigRefPtr &ipconfig) {
+bool Resolver::SetDNSFromIPConfig(const IPConfigRefPtr &ipconfig,
+                                  TimeoutParameters timeout) {
   SLOG(Resolver, 2) << __func__;
 
   CHECK(!path_.empty());
 
   const IPConfig::Properties &props = ipconfig->properties();
 
-  return SetDNSFromLists(props.dns_servers, props.domain_search);
+  return SetDNSFromLists(props.dns_servers, props.domain_search, timeout);
 }
 
 bool Resolver::SetDNSFromLists(const std::vector<std::string> &dns_servers,
-                               const std::vector<std::string> &domain_search) {
+                               const std::vector<std::string> &domain_search,
+                               TimeoutParameters timeout) {
   SLOG(Resolver, 2) << __func__;
 
   if (dns_servers.empty() && domain_search.empty()) {
@@ -64,8 +72,14 @@
 
   // Send queries one-at-a-time, rather than parallelizing IPv4
   // and IPv6 queries for a single host.  Also override the default
-  // 5-second request timeout and use a 1-second tiemout instead.
-  lines.push_back("options single-request timeout:1");
+  // 5-second request timeout and 2 retries.
+  if (timeout == kDefaultTimeout) {
+    lines.push_back(kDefaultTimeoutOptions);
+  } else if (timeout == kShortTimeout) {
+    lines.push_back(kShortTimeoutOptions);
+  } else {
+    NOTIMPLEMENTED() << "Unknown Resolver timeout parameters";
+  }
 
   // Newline at end of file
   lines.push_back("");