summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
authoreroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-16 19:42:46 +0000
committereroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-16 19:42:46 +0000
commit2152600d98b5c802fec1caba84ae9d0cb16af235 (patch)
tree37be46839818f20cfefecf2a284e9352ead55bb8 /net/base
parenta643d62e025c82ad920117e833508f5def0d1deb (diff)
downloadchromium_src-2152600d98b5c802fec1caba84ae9d0cb16af235.zip
chromium_src-2152600d98b5c802fec1caba84ae9d0cb16af235.tar.gz
chromium_src-2152600d98b5c802fec1caba84ae9d0cb16af235.tar.bz2
Log the OS error that getaddrinfo() failed with.
- Display it on the about:net-internals page - Collect it in the histogram Net.OSErrorsForGetAddrinfo. Review URL: http://codereview.chromium.org/2134004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47386 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-rw-r--r--net/base/address_list_unittest.cc2
-rw-r--r--net/base/host_resolver_impl.cc158
-rw-r--r--net/base/host_resolver_impl.h9
-rw-r--r--net/base/host_resolver_impl_unittest.cc10
-rw-r--r--net/base/host_resolver_proc.cc30
-rw-r--r--net/base/host_resolver_proc.h15
-rw-r--r--net/base/mock_host_resolver.cc7
-rw-r--r--net/base/mock_host_resolver.h8
-rw-r--r--net/base/net_log_event_type_list.h6
9 files changed, 199 insertions, 46 deletions
diff --git a/net/base/address_list_unittest.cc b/net/base/address_list_unittest.cc
index 6ebd0f3..6e38c7d 100644
--- a/net/base/address_list_unittest.cc
+++ b/net/base/address_list_unittest.cc
@@ -25,7 +25,7 @@ void CreateAddressList(const std::string& hostname,
int rv = SystemHostResolverProc(hostname,
net::ADDRESS_FAMILY_UNSPECIFIED,
0,
- addrlist);
+ addrlist, NULL);
EXPECT_EQ(0, rv);
addrlist->SetPort(port);
}
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index 5d0a85e..1f89af4 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -4,8 +4,15 @@
#include "net/base/host_resolver_impl.h"
+#if defined(OS_WIN)
+#include <Winsock2.h>
+#elif defined(OS_POSIX)
+#include <netdb.h>
+#endif
+
#include <cmath>
#include <deque>
+#include <vector>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
@@ -15,6 +22,7 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/values.h"
#include "base/worker_pool.h"
#include "net/base/address_list.h"
#include "net/base/host_resolver_proc.h"
@@ -60,18 +68,106 @@ static int ResolveAddrInfo(HostResolverProc* resolver_proc,
const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* out) {
+ AddressList* out,
+ int* os_error) {
if (resolver_proc) {
// Use the custom procedure.
return resolver_proc->Resolve(host, address_family,
- host_resolver_flags, out);
+ host_resolver_flags, out, os_error);
} else {
// Use the system procedure (getaddrinfo).
return SystemHostResolverProc(host, address_family,
- host_resolver_flags, out);
+ host_resolver_flags, out, os_error);
}
}
+// Extra parameters to attach to the NetLog when the resolve failed.
+class HostResolveFailedParams : public NetLog::EventParameters {
+ public:
+ HostResolveFailedParams(int net_error, int os_error, bool was_from_cache)
+ : net_error_(net_error),
+ os_error_(os_error),
+ was_from_cache_(was_from_cache) {
+ }
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger(L"net_error", net_error_);
+ dict->SetBoolean(L"was_from_cache", was_from_cache_);
+
+ if (os_error_) {
+ dict->SetInteger(L"os_error", os_error_);
+#if defined(OS_POSIX)
+ dict->SetString(L"os_error_string", gai_strerror(os_error_));
+#elif defined(OS_WIN)
+ // Map the error code to a human-readable string.
+ LPWSTR error_string = NULL;
+ int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, // Use the internal message table.
+ os_error_,
+ 0, // Use default language.
+ (LPWSTR)&error_string,
+ 0, // Buffer size.
+ 0); // Arguments (unused).
+ dict->SetString(L"os_error_string", error_string);
+ LocalFree(error_string);
+#endif
+ }
+
+ return dict;
+ }
+
+ private:
+ const int net_error_;
+ const int os_error_;
+ const bool was_from_cache_;
+};
+
+// Gets a list of the likely error codes that getaddrinfo() can return
+// (non-exhaustive). These are the error codes that we will track via
+// a histogram.
+std::vector<int> GetAllGetAddrinfoOSErrors() {
+ int os_errors[] = {
+#if defined(OS_POSIX)
+ EAI_ADDRFAMILY,
+ EAI_AGAIN,
+ EAI_BADFLAGS,
+ EAI_FAIL,
+ EAI_FAMILY,
+ EAI_MEMORY,
+ EAI_NODATA,
+ EAI_NONAME,
+ EAI_SERVICE,
+ EAI_SOCKTYPE,
+ EAI_SYSTEM,
+#elif defined(OS_WIN)
+ // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
+ WSA_NOT_ENOUGH_MEMORY,
+ WSAEAFNOSUPPORT,
+ WSAEINVAL,
+ WSAESOCKTNOSUPPORT,
+ WSAHOST_NOT_FOUND,
+ WSANO_DATA,
+ WSANO_RECOVERY,
+ WSANOTINITIALISED,
+ WSATRY_AGAIN,
+ WSATYPE_NOT_FOUND,
+#endif
+ };
+
+ // Histogram enumerations require positive numbers.
+ std::vector<int> errors;
+ for (size_t i = 0; i < arraysize(os_errors); ++i) {
+ errors.push_back(std::abs(os_errors[i]));
+ // Also add N+1 for each error, so the bucket that contains our expected
+ // error is of size 1. That way if we get unexpected error codes, they
+ // won't fall into the same buckets as the expected ones.
+ errors.push_back(std::abs(os_errors[i]) + 1);
+ }
+ return errors;
+}
+
//-----------------------------------------------------------------------------
class HostResolverImpl::Request {
@@ -167,6 +263,7 @@ class HostResolverImpl::Job
origin_loop_(MessageLoop::current()),
resolver_proc_(resolver->effective_resolver_proc()),
error_(OK),
+ os_error_(0),
had_non_speculative_request_(false) {
}
@@ -273,7 +370,8 @@ class HostResolverImpl::Job
key_.hostname,
key_.address_family,
key_.host_resolver_flags,
- &results_);
+ &results_,
+ &os_error_);
// The origin loop could go away while we are trying to post to it, so we
// need to call its PostTask method inside a lock. See ~HostResolver.
@@ -301,6 +399,11 @@ class HostResolverImpl::Job
// requests.
}
+ if (error_ != OK) {
+ UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.OSErrorsForGetAddrinfo",
+ std::abs(os_error_),
+ GetAllGetAddrinfoOSErrors());
+ }
if (was_cancelled())
return;
@@ -311,7 +414,7 @@ class HostResolverImpl::Job
if (error_ == OK)
results_.SetPort(requests_[0]->port());
- resolver_->OnJobComplete(this, error_, results_);
+ resolver_->OnJobComplete(this, error_, os_error_, results_);
}
// Immutable. Can be read from either thread,
@@ -336,6 +439,7 @@ class HostResolverImpl::Job
// Assigned on the worker thread, read on the origin thread.
int error_;
+ int os_error_;
// True if a non-speculative request was ever attached to this job
// (regardless of whether or not it was later cancelled.
@@ -669,23 +773,26 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
const HostCache::Entry* cache_entry = cache_->Lookup(
key, base::TimeTicks::Now());
if (cache_entry) {
- int error = cache_entry->error;
- if (error == OK)
+ int net_error = cache_entry->error;
+ if (net_error == OK)
addresses->SetFrom(cache_entry->addrlist, info.port());
// Update the net log and notify registered observers.
- OnFinishRequest(net_log, request_id, info, error);
+ OnFinishRequest(net_log, request_id, info, net_error,
+ 0, /* os_error (unknown since from cache) */
+ true /* was_from_cache */);
- return error;
+ return net_error;
}
}
// If no callback was specified, do a synchronous resolution.
if (!callback) {
AddressList addrlist;
+ int os_error = 0;
int error = ResolveAddrInfo(
effective_resolver_proc(), key.hostname, key.address_family,
- key.host_resolver_flags, &addrlist);
+ key.host_resolver_flags, &addrlist, &os_error);
if (error == OK) {
addrlist.SetPort(info.port());
*addresses = addrlist;
@@ -696,7 +803,8 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
cache_->Set(key, error, addrlist, base::TimeTicks::Now());
// Update the net log and notify registered observers.
- OnFinishRequest(net_log, request_id, info, error);
+ OnFinishRequest(net_log, request_id, info, error, os_error,
+ false /* was_from_cache */);
return error;
}
@@ -833,13 +941,14 @@ void HostResolverImpl::RemoveOutstandingJob(Job* job) {
}
void HostResolverImpl::OnJobComplete(Job* job,
- int error,
+ int net_error,
+ int os_error,
const AddressList& addrlist) {
RemoveOutstandingJob(job);
// Write result to the cache.
if (cache_.get())
- cache_->Set(job->key(), error, addrlist, base::TimeTicks::Now());
+ cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
// Make a note that we are executing within OnJobComplete() in case the
// HostResolver is deleted by a callback invocation.
@@ -857,9 +966,10 @@ void HostResolverImpl::OnJobComplete(Job* job,
DCHECK_EQ(job, req->job());
// Update the net log and notify registered observers.
- OnFinishRequest(req->net_log(), req->id(), req->info(), error);
+ OnFinishRequest(req->net_log(), req->id(), req->info(), net_error,
+ os_error, false /* was_from_cache */);
- req->OnComplete(error, addrlist);
+ req->OnComplete(net_error, addrlist);
// Check if the job was cancelled as a result of running the callback.
// (Meaning that |this| was deleted).
@@ -888,17 +998,25 @@ void HostResolverImpl::OnStartRequest(const BoundNetLog& net_log,
void HostResolverImpl::OnFinishRequest(const BoundNetLog& net_log,
int request_id,
const RequestInfo& info,
- int error) {
+ int net_error,
+ int os_error,
+ bool was_from_cache) {
+ bool was_resolved = net_error == OK;
+
// Notify the observers of the completion.
if (!observers_.empty()) {
- bool was_resolved = error == OK;
for (ObserversList::iterator it = observers_.begin();
it != observers_.end(); ++it) {
(*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
}
}
- net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
+ // Log some extra parameters on failure.
+ scoped_refptr<NetLog::EventParameters> params;
+ if (!was_resolved)
+ params = new HostResolveFailedParams(net_error, os_error, was_from_cache);
+
+ net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, params);
}
void HostResolverImpl::OnCancelRequest(const BoundNetLog& net_log,
@@ -1020,7 +1138,9 @@ int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
Request* r = req_evicted_from_queue.get();
int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
- OnFinishRequest(r->net_log(), r->id(), r->info(), error);
+ OnFinishRequest(r->net_log(), r->id(), r->info(), error,
+ 0, /* os_error (not applicable) */
+ false /* was_from_cache */);
if (r == req)
return error;
diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h
index 938e52f..417cc77 100644
--- a/net/base/host_resolver_impl.h
+++ b/net/base/host_resolver_impl.h
@@ -150,8 +150,9 @@ class HostResolverImpl : public HostResolver,
// Removes |job| from the outstanding jobs list.
void RemoveOutstandingJob(Job* job);
- // Callback for when |job| has completed with |error| and |addrlist|.
- void OnJobComplete(Job* job, int error, const AddressList& addrlist);
+ // Callback for when |job| has completed with |net_error| and |addrlist|.
+ void OnJobComplete(Job* job, int net_error, int os_error,
+ const AddressList& addrlist);
// Called when a request has just been started.
void OnStartRequest(const BoundNetLog& net_log,
@@ -162,7 +163,9 @@ class HostResolverImpl : public HostResolver,
void OnFinishRequest(const BoundNetLog& net_log,
int request_id,
const RequestInfo& info,
- int error);
+ int net_error,
+ int os_error,
+ bool was_from_cache);
// Called when a request has been cancelled.
void OnCancelRequest(const BoundNetLog& net_log,
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index ce1ae3b..3d7e02a 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -91,14 +91,15 @@ class CapturingHostResolverProc : public HostResolverProc {
virtual int Resolve(const std::string& hostname,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist) {
+ AddressList* addrlist,
+ int* os_error) {
event_.Wait();
{
AutoLock l(lock_);
capture_list_.push_back(CaptureEntry(hostname, address_family));
}
return ResolveUsingPrevious(hostname, address_family,
- host_resolver_flags, addrlist);
+ host_resolver_flags, addrlist, os_error);
}
CaptureList GetCaptureList() const {
@@ -137,7 +138,8 @@ class EchoingHostResolverProc : public HostResolverProc {
virtual int Resolve(const std::string& hostname,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist) {
+ AddressList* addrlist,
+ int* os_error) {
// Encode the request's hostname and address_family in the output address.
std::string ip_literal = StringPrintf("192.%d.%d.%d",
static_cast<int>(hostname.size()),
@@ -147,7 +149,7 @@ class EchoingHostResolverProc : public HostResolverProc {
return SystemHostResolverProc(ip_literal,
ADDRESS_FAMILY_UNSPECIFIED,
host_resolver_flags,
- addrlist);
+ addrlist, os_error);
}
};
diff --git a/net/base/host_resolver_proc.cc b/net/base/host_resolver_proc.cc
index 84daae0..804135c 100644
--- a/net/base/host_resolver_proc.cc
+++ b/net/base/host_resolver_proc.cc
@@ -71,14 +71,16 @@ int HostResolverProc::ResolveUsingPrevious(
const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist) {
- if (previous_proc_)
- return previous_proc_->Resolve(host, address_family,
- host_resolver_flags, addrlist);
+ AddressList* addrlist,
+ int* os_error) {
+ if (previous_proc_) {
+ return previous_proc_->Resolve(host, address_family, host_resolver_flags,
+ addrlist, os_error);
+ }
// Final fallback is the system resolver.
- return SystemHostResolverProc(host, address_family,
- host_resolver_flags, addrlist);
+ return SystemHostResolverProc(host, address_family, host_resolver_flags,
+ addrlist, os_error);
}
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
@@ -157,7 +159,11 @@ ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);
int SystemHostResolverProc(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist) {
+ AddressList* addrlist,
+ int* os_error) {
+ if (os_error)
+ *os_error = 0;
+
// The result of |getaddrinfo| for empty hosts is inconsistent across systems.
// On Windows it gives the default interface's address, whereas on Linux it
// gives an error. We will make it fail on all platforms for consistency.
@@ -228,8 +234,16 @@ int SystemHostResolverProc(const std::string& host,
}
#endif
- if (err)
+ if (err) {
+ if (os_error) {
+#if defined(OS_WIN)
+ *os_error = WSAGetLastError();
+#else
+ *os_error = err;
+#endif
+ }
return ERR_NAME_NOT_RESOLVED;
+ }
addrlist->Adopt(ai);
return OK;
diff --git a/net/base/host_resolver_proc.h b/net/base/host_resolver_proc.h
index 6f32280..3a8adc7 100644
--- a/net/base/host_resolver_proc.h
+++ b/net/base/host_resolver_proc.h
@@ -27,11 +27,13 @@ class HostResolverProc : public base::RefCountedThreadSafe<HostResolverProc> {
// Resolves |host| to an address list, restricting the results to addresses
// in |address_family|. If successful returns OK and fills |addrlist| with
- // a list of socket addresses. Otherwise returns a network error code.
+ // a list of socket addresses. Otherwise returns a network error code, and
+ // fills |os_error| with a more specific error if it was non-NULL.
virtual int Resolve(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist) = 0;
+ AddressList* addrlist,
+ int* os_error) = 0;
protected:
friend class base::RefCountedThreadSafe<HostResolverProc>;
@@ -42,7 +44,8 @@ class HostResolverProc : public base::RefCountedThreadSafe<HostResolverProc> {
int ResolveUsingPrevious(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist);
+ AddressList* addrlist,
+ int* os_error);
private:
friend class HostResolverImpl;
@@ -77,11 +80,13 @@ class HostResolverProc : public base::RefCountedThreadSafe<HostResolverProc> {
// Resolves |host| to an address list, using the system's default host resolver.
// (i.e. this calls out to getaddrinfo()). If successful returns OK and fills
// |addrlist| with a list of socket addresses. Otherwise returns a
-// network error code.
+// network error code, and fills |os_error| with a more specific errir if it
+// was non-NULL.
int SystemHostResolverProc(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist);
+ AddressList* addrlist,
+ int* os_error);
} // namespace net
diff --git a/net/base/mock_host_resolver.cc b/net/base/mock_host_resolver.cc
index 573d57e..b16b304 100644
--- a/net/base/mock_host_resolver.cc
+++ b/net/base/mock_host_resolver.cc
@@ -230,7 +230,8 @@ void RuleBasedHostResolverProc::AddSimulatedFailure(
int RuleBasedHostResolverProc::Resolve(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist) {
+ AddressList* addrlist,
+ int* os_error) {
RuleList::iterator r;
for (r = rules_.begin(); r != rules_.end(); ++r) {
bool matches_address_family =
@@ -259,7 +260,7 @@ int RuleBasedHostResolverProc::Resolve(const std::string& host,
return SystemHostResolverProc(effective_host,
address_family,
host_resolver_flags,
- addrlist);
+ addrlist, os_error);
case Rule::kResolverTypeIPV6Literal:
return CreateIPv6Address(effective_host, r->canonical_name, addrlist);
case Rule::kResolverTypeIPV4Literal:
@@ -271,7 +272,7 @@ int RuleBasedHostResolverProc::Resolve(const std::string& host,
}
}
return ResolveUsingPrevious(host, address_family,
- host_resolver_flags, addrlist);
+ host_resolver_flags, addrlist, os_error);
}
//-----------------------------------------------------------------------------
diff --git a/net/base/mock_host_resolver.h b/net/base/mock_host_resolver.h
index ad89a48..1fe4f06 100644
--- a/net/base/mock_host_resolver.h
+++ b/net/base/mock_host_resolver.h
@@ -143,7 +143,8 @@ class RuleBasedHostResolverProc : public HostResolverProc {
virtual int Resolve(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist);
+ AddressList* addrlist,
+ int* os_error);
private:
~RuleBasedHostResolverProc();
@@ -168,10 +169,11 @@ class WaitingHostResolverProc : public HostResolverProc {
virtual int Resolve(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist) {
+ AddressList* addrlist,
+ int* os_error) {
event_.Wait();
return ResolveUsingPrevious(host, address_family, host_resolver_flags,
- addrlist);
+ addrlist, os_error);
}
private:
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 5ec710c..6b4a7e2 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -26,6 +26,12 @@ EVENT_TYPE(REQUEST_ALIVE)
// ------------------------------------------------------------------------
// The start/end of a host resolve (DNS) request.
+// If an error occurred, the end phase will contain these parameters:
+// {
+// "net_error": <The net error code integer for the failure>,
+// "os_error": <The exact error code integer that getaddrinfo() returned>,
+// "was_from_cache": <True if the response was gotten from the cache>
+// }
EVENT_TYPE(HOST_RESOLVER_IMPL)
// ------------------------------------------------------------------------