diff options
author | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-16 19:42:46 +0000 |
---|---|---|
committer | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-16 19:42:46 +0000 |
commit | 2152600d98b5c802fec1caba84ae9d0cb16af235 (patch) | |
tree | 37be46839818f20cfefecf2a284e9352ead55bb8 /net/base | |
parent | a643d62e025c82ad920117e833508f5def0d1deb (diff) | |
download | chromium_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.cc | 2 | ||||
-rw-r--r-- | net/base/host_resolver_impl.cc | 158 | ||||
-rw-r--r-- | net/base/host_resolver_impl.h | 9 | ||||
-rw-r--r-- | net/base/host_resolver_impl_unittest.cc | 10 | ||||
-rw-r--r-- | net/base/host_resolver_proc.cc | 30 | ||||
-rw-r--r-- | net/base/host_resolver_proc.h | 15 | ||||
-rw-r--r-- | net/base/mock_host_resolver.cc | 7 | ||||
-rw-r--r-- | net/base/mock_host_resolver.h | 8 | ||||
-rw-r--r-- | net/base/net_log_event_type_list.h | 6 |
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) // ------------------------------------------------------------------------ |