summaryrefslogtreecommitdiffstats
path: root/net/base/host_resolver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/base/host_resolver.cc')
-rw-r--r--net/base/host_resolver.cc141
1 files changed, 85 insertions, 56 deletions
diff --git a/net/base/host_resolver.cc b/net/base/host_resolver.cc
index 101c5ec..6d79b46 100644
--- a/net/base/host_resolver.cc
+++ b/net/base/host_resolver.cc
@@ -32,7 +32,9 @@
#include <ws2tcpip.h>
#include <wspiapi.h> // Needed for Win2k compat.
+#include "base/message_loop.h"
#include "base/string_util.h"
+#include "base/worker_pool.h"
#include "net/base/address_list.h"
#include "net/base/net_errors.h"
#include "net/base/winsock_init.h"
@@ -56,58 +58,94 @@ static int ResolveAddrInfo(const std::string& host, const std::string& port,
//-----------------------------------------------------------------------------
-struct HostResolver::Request :
+class HostResolver::Request :
public base::RefCountedThreadSafe<HostResolver::Request> {
- Request() : error(OK), results(NULL) {
- DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
- GetCurrentProcess(), &origin_thread,
- 0, FALSE, DUPLICATE_SAME_ACCESS);
+ public:
+ Request(HostResolver* resolver,
+ const std::string& host,
+ const std::string& port,
+ AddressList* addresses,
+ CompletionCallback* callback)
+ : host_(host),
+ port_(port),
+ resolver_(resolver),
+ addresses_(addresses),
+ callback_(callback),
+ origin_loop_(MessageLoop::current()),
+ error_(OK),
+ results_(NULL) {
}
+
~Request() {
- CloseHandle(origin_thread);
+ if (results_)
+ freeaddrinfo(results_);
}
- // Only used on the origin thread (where Resolve was called).
- AddressList* addresses;
- CompletionCallback* callback;
+ void DoLookup() {
+ // Running on the worker thread
+ error_ = ResolveAddrInfo(host_, port_, &results_);
- // Set on the origin thread, read on the worker thread.
- std::string host;
- std::string port;
- HANDLE origin_thread;
-
- // Assigned on the worker thread.
- int error;
- struct addrinfo* results;
-
- static void CALLBACK ReturnResults(ULONG_PTR param) {
- Request* r = reinterpret_cast<Request*>(param);
- // The HostResolver may have gone away.
- if (r->addresses) {
- if (r->error == OK)
- r->addresses->Adopt(r->results);
- if (r->callback)
- r->callback->Run(r->error);
- } else if (r->results) {
- freeaddrinfo(r->results);
+ Task* reply = NewRunnableMethod(this, &Request::DoCallback);
+
+ // 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.
+ {
+ AutoLock locked(origin_loop_lock_);
+ if (origin_loop_) {
+ origin_loop_->PostTask(FROM_HERE, reply);
+ reply = NULL;
+ }
}
- r->Release();
+
+ // Does nothing if it got posted.
+ delete reply;
}
- static DWORD WINAPI DoLookup(void* param) {
- Request* r = static_cast<Request*>(param);
+ void DoCallback() {
+ // Running on the origin thread.
+ DCHECK(error_ || results_);
- r->error = ResolveAddrInfo(r->host, r->port, &r->results);
+ // We may have been cancelled!
+ if (!resolver_)
+ return;
- if (!QueueUserAPC(ReturnResults, r->origin_thread,
- reinterpret_cast<ULONG_PTR>(param))) {
- // The origin thread must have gone away.
- if (r->results)
- freeaddrinfo(r->results);
- r->Release();
+ if (!error_) {
+ addresses_->Adopt(results_);
+ results_ = NULL;
}
- return 0;
+
+ // Drop the resolver's reference to us. Do this before running the
+ // callback since the callback might result in the resolver being
+ // destroyed.
+ resolver_->request_ = NULL;
+
+ callback_->Run(error_);
+ }
+
+ void Cancel() {
+ resolver_ = NULL;
+
+ AutoLock locked(origin_loop_lock_);
+ origin_loop_ = NULL;
}
+
+ private:
+ // Set on the origin thread, read on the worker thread.
+ std::string host_;
+ std::string port_;
+
+ // Only used on the origin thread (where Resolve was called).
+ HostResolver* resolver_;
+ AddressList* addresses_;
+ CompletionCallback* callback_;
+
+ // Used to post ourselves onto the origin thread.
+ Lock origin_loop_lock_;
+ MessageLoop* origin_loop_;
+
+ // Assigned on the worker thread, read on the origin thread.
+ int error_;
+ struct addrinfo* results_;
};
//-----------------------------------------------------------------------------
@@ -117,17 +155,14 @@ HostResolver::HostResolver() {
}
HostResolver::~HostResolver() {
- if (request_) {
- // Prevent the thread pool from running the callback.
- request_->addresses = NULL;
- request_->callback = NULL;
- }
+ if (request_)
+ request_->Cancel();
}
int HostResolver::Resolve(const std::string& hostname, int port,
AddressList* addresses,
CompletionCallback* callback) {
- DCHECK(!request_);
+ DCHECK(!request_) << "resolver already in use";
const std::string& port_str = IntToString(port);
@@ -140,18 +175,12 @@ int HostResolver::Resolve(const std::string& hostname, int port,
return rv;
}
+ request_ = new Request(this, hostname, port_str, addresses, callback);
+
// Dispatch to worker thread...
- request_ = new Request();
- request_->host = hostname;
- request_->port = port_str;
- request_->addresses = addresses;
- request_->callback = callback;
-
- // Balanced in Request::ReturnResults (or DoLookup if there is an error).
- request_->AddRef();
- if (!QueueUserWorkItem(Request::DoLookup, request_, WT_EXECUTELONGFUNCTION)) {
- DLOG(ERROR) << "QueueUserWorkItem failed: " << GetLastError();
- request_->Release();
+ if (!WorkerPool::PostTask(FROM_HERE,
+ NewRunnableMethod(request_.get(), &Request::DoLookup), true)) {
+ NOTREACHED();
request_ = NULL;
return ERR_FAILED;
}