1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/socket/client_socket_handle.h" 6 7 #include "base/compiler_specific.h" 8 #include "base/metrics/histogram.h" 9 #include "base/logging.h" 10 #include "net/base/net_errors.h" 11 #include "net/socket/client_socket_pool.h" 12 #include "net/socket/client_socket_pool_histograms.h" 13 14 namespace net { 15 16 ClientSocketHandle::ClientSocketHandle() 17 : is_initialized_(false), 18 is_reused_(false), 19 ALLOW_THIS_IN_INITIALIZER_LIST( 20 callback_(this, &ClientSocketHandle::OnIOComplete)), 21 is_ssl_error_(false) {} 22 23 ClientSocketHandle::~ClientSocketHandle() { 24 Reset(); 25 } 26 27 void ClientSocketHandle::Reset() { 28 ResetInternal(true); 29 ResetErrorState(); 30 } 31 32 void ClientSocketHandle::ResetInternal(bool cancel) { 33 if (group_name_.empty()) // Was Init called? 34 return; 35 if (is_initialized()) { 36 // Because of http://crbug.com/37810 we may not have a pool, but have 37 // just a raw socket. 38 socket_->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE, NULL); 39 if (pool_) 40 // If we've still got a socket, release it back to the ClientSocketPool so 41 // it can be deleted or reused. 42 pool_->ReleaseSocket(group_name_, release_socket(), pool_id_); 43 } else if (cancel) { 44 // If we did not get initialized yet, we've got a socket request pending. 45 // Cancel it. 46 pool_->CancelRequest(group_name_, this); 47 } 48 is_initialized_ = false; 49 group_name_.clear(); 50 is_reused_ = false; 51 user_callback_ = NULL; 52 pool_ = NULL; 53 idle_time_ = base::TimeDelta(); 54 init_time_ = base::TimeTicks(); 55 setup_time_ = base::TimeDelta(); 56 pool_id_ = -1; 57 } 58 59 void ClientSocketHandle::ResetErrorState() { 60 is_ssl_error_ = false; 61 ssl_error_response_info_ = HttpResponseInfo(); 62 pending_http_proxy_connection_.reset(); 63 } 64 65 LoadState ClientSocketHandle::GetLoadState() const { 66 CHECK(!is_initialized()); 67 CHECK(!group_name_.empty()); 68 // Because of http://crbug.com/37810 we may not have a pool, but have 69 // just a raw socket. 70 if (!pool_) 71 return LOAD_STATE_IDLE; 72 return pool_->GetLoadState(group_name_, this); 73 } 74 75 void ClientSocketHandle::OnIOComplete(int result) { 76 CompletionCallback* callback = user_callback_; 77 user_callback_ = NULL; 78 HandleInitCompletion(result); 79 callback->Run(result); 80 } 81 82 void ClientSocketHandle::HandleInitCompletion(int result) { 83 CHECK_NE(ERR_IO_PENDING, result); 84 if (result != OK) { 85 if (!socket_.get()) 86 ResetInternal(false); // Nothing to cancel since the request failed. 87 else 88 is_initialized_ = true; 89 return; 90 } 91 is_initialized_ = true; 92 CHECK_NE(-1, pool_id_) << "Pool should have set |pool_id_| to a valid value."; 93 setup_time_ = base::TimeTicks::Now() - init_time_; 94 95 ClientSocketPoolHistograms* histograms = pool_->histograms(); 96 histograms->AddSocketType(reuse_type()); 97 switch (reuse_type()) { 98 case ClientSocketHandle::UNUSED: 99 histograms->AddRequestTime(setup_time()); 100 break; 101 case ClientSocketHandle::UNUSED_IDLE: 102 histograms->AddUnusedIdleTime(idle_time()); 103 break; 104 case ClientSocketHandle::REUSED_IDLE: 105 histograms->AddReusedIdleTime(idle_time()); 106 break; 107 default: 108 NOTREACHED(); 109 break; 110 } 111 112 // Broadcast that the socket has been acquired. 113 // TODO(eroman): This logging is not complete, in particular set_socket() and 114 // release() socket. It ends up working though, since those methods are being 115 // used to layer sockets (and the destination sources are the same). 116 DCHECK(socket_.get()); 117 socket_->NetLog().BeginEvent( 118 NetLog::TYPE_SOCKET_IN_USE, 119 make_scoped_refptr(new NetLogSourceParameter( 120 "source_dependency", requesting_source_))); 121 } 122 123 } // namespace net 124