Refactor ConnectJob and TCPConnectJob.
ConnectJob will only call OnConnectJobComplete() on asynchronous completion.
TCPConnectJob now uses DoLoop() internally.
BUG=http://crbug.com/13289
TEST=none

Review URL: http://codereview.chromium.org/151118

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19789 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 123c3cf..56eb1ab7 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -30,6 +30,20 @@
 
 namespace net {
 
+ConnectJob::ConnectJob(const std::string& group_name,
+                       const ClientSocketHandle* key_handle,
+                       Delegate* delegate)
+    : group_name_(group_name),
+      key_handle_(key_handle),
+      delegate_(delegate),
+      load_state_(LOAD_STATE_IDLE) {
+  DCHECK(!group_name.empty());
+  DCHECK(key_handle);
+  DCHECK(delegate);
+}
+
+ConnectJob::~ConnectJob() {}
+
 ClientSocketPoolBase::ClientSocketPoolBase(
     int max_sockets_per_group,
     ConnectJobFactory* connect_job_factory)
@@ -70,29 +84,21 @@
   DCHECK(callback);
   Group& group = group_map_[group_name];
 
-  CheckSocketCounts(group);
-
   // Can we make another active socket now?
-  if (group.active_socket_count == max_sockets_per_group_) {
+  if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) {
     CHECK(callback);
     Request r(handle, callback, priority, resolve_info);
     InsertRequestIntoQueue(r, &group.pending_requests);
     return ERR_IO_PENDING;
   }
 
-  // OK, we are going to activate one.
-  group.active_socket_count++;
-
   while (!group.idle_sockets.empty()) {
     IdleSocket idle_socket = group.idle_sockets.back();
     group.idle_sockets.pop_back();
     DecrementIdleCount();
     if (idle_socket.socket->IsConnectedAndIdle()) {
       // We found one we can reuse!
-      handle->set_socket(idle_socket.socket);
-      handle->set_is_reused(true);
-      group.sockets_handed_out_count++;
-      CheckSocketCounts(group);
+      HandOutSocket(idle_socket.socket, true /* reuse */, handle, &group);
       return OK;
     }
     delete idle_socket.socket;
@@ -102,14 +108,23 @@
 
   CHECK(callback);
   Request r(handle, callback, priority, resolve_info);
-  group.connecting_requests[handle] = r;
+  scoped_ptr<ConnectJob> connect_job(
+      connect_job_factory_->NewConnectJob(group_name, r, this));
 
-  CHECK(!ContainsKey(connect_job_map_, handle));
+  int rv = connect_job->Connect();
+  if (rv == OK) {
+    HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
+                  handle, &group);
+  } else if (rv == ERR_IO_PENDING) {
+    group.connecting_requests[handle] = r;
+    CHECK(!ContainsKey(connect_job_map_, handle));
+    connect_job_map_[handle] = connect_job.release();
+  } else {
+    if (group.IsEmpty())
+      group_map_.erase(group_name);
+  }
 
-  ConnectJob* connect_job =
-      connect_job_factory_->NewConnectJob(group_name, r, this);
-  connect_job_map_[handle] = connect_job;
-  return connect_job->Connect();
+  return rv;
 }
 
 void ClientSocketPoolBase::CancelRequest(const std::string& group_name,
@@ -118,8 +133,6 @@
 
   Group& group = group_map_[group_name];
 
-  CheckSocketCounts(group);
-
   // Search pending_requests for matching handle.
   RequestQueue::iterator it = group.pending_requests.begin();
   for (; it != group.pending_requests.end(); ++it) {
@@ -136,7 +149,7 @@
   if (map_it != group.connecting_requests.end()) {
     RemoveConnectJob(handle);
     group.connecting_requests.erase(map_it);
-    RemoveActiveSocket(group_name, &group);
+    OnAvailableSocketSlot(group_name, &group);
   }
 }
 
@@ -229,9 +242,8 @@
     }
 
     // Delete group if no longer needed.
-    if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
+    if (group.IsEmpty()) {
       CHECK(group.pending_requests.empty());
-      CHECK(group.connecting_requests.empty());
       group_map_.erase(i++);
     } else {
       ++i;
@@ -258,9 +270,7 @@
   Group& group = i->second;
 
   CHECK(group.active_socket_count > 0);
-  CheckSocketCounts(group);
-
-  group.sockets_handed_out_count--;
+  group.active_socket_count--;
 
   const bool can_reuse = socket->IsConnectedAndIdle();
   if (can_reuse) {
@@ -274,53 +284,37 @@
     delete socket;
   }
 
-  RemoveActiveSocket(group_name, &group);
+  OnAvailableSocketSlot(group_name, &group);
 }
 
-void ClientSocketPoolBase::OnConnectJobComplete(
-    const std::string& group_name,
-    const ClientSocketHandle* key_handle,
-    ClientSocket* socket,
-    int result,
-    bool was_async) {
+void ClientSocketPoolBase::OnConnectJobComplete(int result, ConnectJob* job) {
+  DCHECK_NE(ERR_IO_PENDING, result);
+  const std::string group_name = job->group_name();
   GroupMap::iterator group_it = group_map_.find(group_name);
   CHECK(group_it != group_map_.end());
   Group& group = group_it->second;
 
-  CheckSocketCounts(group);
-
   RequestMap* request_map = &group.connecting_requests;
 
-  RequestMap::iterator it = request_map->find(key_handle);
+  RequestMap::iterator it = request_map->find(job->key_handle());
   CHECK(it != request_map->end());
-  Request request = it->second;
+  ClientSocketHandle* const handle = it->second.handle;
+  CompletionCallback* const callback = it->second.callback;
   request_map->erase(it);
-  DCHECK_EQ(request.handle, key_handle);
+  DCHECK_EQ(handle, job->key_handle());
 
-  if (!socket) {
-    RemoveActiveSocket(group_name, &group);
+  ClientSocket* const socket = job->ReleaseSocket();
+  RemoveConnectJob(job->key_handle());
+
+  if (result != OK) {
+    callback->Run(result);  // |group| is not necessarily valid after this.
+    // |group| may be invalid after the callback, we need to search
+    // |group_map_| again.
+    MaybeOnAvailableSocketSlot(group_name);
   } else {
-    request.handle->set_socket(socket);
-    request.handle->set_is_reused(false);
-    group.sockets_handed_out_count++;
-
-    CheckSocketCounts(group);
+    HandOutSocket(socket, false /* not reused */, handle, &group);
+    callback->Run(result);
   }
-
-  RemoveConnectJob(request.handle);
-
-  if (was_async)
-    request.callback->Run(result);
-}
-
-// static
-void ClientSocketPoolBase::CheckSocketCounts(const Group& group) {
-  CHECK(group.active_socket_count ==
-        group.sockets_handed_out_count +
-        static_cast<int>(group.connecting_requests.size()))
-      << "[active_socket_count: " << group.active_socket_count
-      << " ] [sockets_handed_out_count: " << group.sockets_handed_out_count
-      << " ] [connecting_requests size: " << group.connecting_requests.size();
 }
 
 void ClientSocketPoolBase::RemoveConnectJob(
@@ -331,20 +325,25 @@
   connect_job_map_.erase(it);
 }
 
-void ClientSocketPoolBase::RemoveActiveSocket(const std::string& group_name,
-                                              Group* group) {
-  group->active_socket_count--;
+void ClientSocketPoolBase::MaybeOnAvailableSocketSlot(
+    const std::string& group_name) {
+  GroupMap::iterator it = group_map_.find(group_name);
+  if (it != group_map_.end()) {
+    Group& group = it->second;
+    if (group.HasAvailableSocketSlot(max_sockets_per_group_))
+      OnAvailableSocketSlot(group_name, &group);
+  }
+}
 
+void ClientSocketPoolBase::OnAvailableSocketSlot(const std::string& group_name,
+                                                 Group* group) {
   if (!group->pending_requests.empty()) {
     ProcessPendingRequest(group_name, group);
     // |group| may no longer be valid after this point.  Be careful not to
     // access it again.
-  } else if (group->active_socket_count == 0 && group->idle_sockets.empty()) {
+  } else if (group->IsEmpty()) {
     // Delete |group| if no longer needed.  |group| will no longer be valid.
-    DCHECK(group->connecting_requests.empty());
     group_map_.erase(group_name);
-  } else {
-    CheckSocketCounts(*group);
   }
 }
 
@@ -356,10 +355,25 @@
   int rv = RequestSocket(
       group_name, r.resolve_info, r.priority, r.handle, r.callback);
 
-  // |group| may be invalid after RequestSocket.
-
-  if (rv != ERR_IO_PENDING)
+  if (rv != ERR_IO_PENDING) {
     r.callback->Run(rv);
+    if (rv != OK) {
+      // |group| may be invalid after the callback, we need to search
+      // |group_map_| again.
+      MaybeOnAvailableSocketSlot(group_name);
+    }
+  }
+}
+
+void ClientSocketPoolBase::HandOutSocket(
+    ClientSocket* socket,
+    bool reused,
+    ClientSocketHandle* handle,
+    Group* group) {
+  DCHECK(socket);
+  handle->set_socket(socket);
+  handle->set_is_reused(reused);
+  group->active_socket_count++;
 }
 
 }  // namespace net