Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "jingle/notifier/base/chrome_async_socket.h" | 5 #include "jingle/notifier/base/chrome_async_socket.h" |
| 6 | 6 |
| 7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
| 8 #include <winsock2.h> | 8 #include <winsock2.h> |
| 9 #elif defined(OS_POSIX) | 9 #elif defined(OS_POSIX) |
| 10 #include <arpa/inet.h> | 10 #include <arpa/inet.h> |
| 11 #endif | 11 #endif |
| 12 | 12 |
| 13 #include <algorithm> | 13 #include <algorithm> |
| 14 #include <cstring> | 14 #include <cstring> |
| 15 #include <cstdlib> | 15 #include <cstdlib> |
| 16 | 16 |
| 17 #include "base/basictypes.h" | 17 #include "base/basictypes.h" |
| 18 #include "base/compiler_specific.h" | 18 #include "base/compiler_specific.h" |
| 19 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/message_loop.h" | 20 #include "base/message_loop.h" |
| 21 #include "jingle/notifier/base/fake_ssl_client_socket.h" | |
| 21 #include "net/base/address_list.h" | 22 #include "net/base/address_list.h" |
| 22 #include "net/base/host_port_pair.h" | 23 #include "net/base/host_port_pair.h" |
| 23 #include "net/base/io_buffer.h" | 24 #include "net/base/io_buffer.h" |
| 24 #include "net/base/net_util.h" | 25 #include "net/base/net_util.h" |
| 25 #include "net/base/ssl_config_service.h" | 26 #include "net/base/ssl_config_service.h" |
| 26 #include "net/base/sys_addrinfo.h" | 27 #include "net/base/sys_addrinfo.h" |
| 28 #include "net/http/http_network_session.h" | |
| 27 #include "net/socket/client_socket_factory.h" | 29 #include "net/socket/client_socket_factory.h" |
| 30 #include "net/socket/client_socket_handle.h" | |
| 31 #include "net/socket/client_socket_pool_manager.h" | |
| 28 #include "net/socket/ssl_client_socket.h" | 32 #include "net/socket/ssl_client_socket.h" |
| 29 #include "net/socket/tcp_client_socket.h" | 33 #include "net/socket/tcp_client_socket.h" |
| 34 #include "net/url_request/url_request_context.h" | |
| 35 #include "net/url_request/url_request_context_getter.h" | |
| 30 #include "talk/base/socketaddress.h" | 36 #include "talk/base/socketaddress.h" |
| 31 | 37 |
| 32 namespace notifier { | 38 namespace notifier { |
| 33 | 39 |
| 34 ChromeAsyncSocket::ChromeAsyncSocket( | 40 ChromeAsyncSocket::ChromeAsyncSocket( |
| 35 net::ClientSocketFactory* client_socket_factory, | |
| 36 const net::SSLConfig& ssl_config, | 41 const net::SSLConfig& ssl_config, |
| 37 net::CertVerifier* cert_verifier, | 42 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, |
|
akalin
2011/04/13 20:49:32
It seems to me that a socket shouldn't need to kno
sanjeevr
2011/04/13 21:20:21
This is not straightforward. Basically there is co
| |
| 43 bool use_fake_ssl_client_socket, | |
| 38 size_t read_buf_size, | 44 size_t read_buf_size, |
| 39 size_t write_buf_size, | 45 size_t write_buf_size, |
| 40 net::NetLog* net_log) | 46 net::NetLog* net_log) |
| 41 : connect_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), | 47 : proxy_resolve_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), |
| 48 &ChromeAsyncSocket::ProcessProxyResolveDone), | |
| 49 connect_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), | |
| 42 &ChromeAsyncSocket::ProcessConnectDone), | 50 &ChromeAsyncSocket::ProcessConnectDone), |
| 43 read_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), | 51 read_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), |
| 44 &ChromeAsyncSocket::ProcessReadDone), | 52 &ChromeAsyncSocket::ProcessReadDone), |
| 45 write_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), | 53 write_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), |
| 46 &ChromeAsyncSocket::ProcessWriteDone), | 54 &ChromeAsyncSocket::ProcessWriteDone), |
| 47 ssl_connect_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), | 55 ssl_connect_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), |
| 48 &ChromeAsyncSocket::ProcessSSLConnectDone), | 56 &ChromeAsyncSocket::ProcessSSLConnectDone), |
| 49 client_socket_factory_(client_socket_factory), | 57 fake_ssl_handshake_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), |
|
akalin
2011/04/13 20:49:32
i don't think ChromeAsyncSocket should know anythi
sanjeevr
2011/04/13 21:20:21
Yes, we can supply this layer externally.
| |
| 58 &ChromeAsyncSocket::ProcessFakeSSLHandshakeDone), | |
| 50 ssl_config_(ssl_config), | 59 ssl_config_(ssl_config), |
| 51 cert_verifier_(cert_verifier), | 60 request_context_getter_(request_context_getter), |
| 61 use_fake_ssl_client_socket_(use_fake_ssl_client_socket), | |
| 52 bound_net_log_( | 62 bound_net_log_( |
| 53 net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), | 63 net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), |
| 54 state_(STATE_CLOSED), | 64 state_(STATE_CLOSED), |
| 55 error_(ERROR_NONE), | 65 error_(ERROR_NONE), |
| 56 net_error_(net::OK), | 66 net_error_(net::OK), |
| 57 scoped_runnable_method_factory_( | 67 scoped_runnable_method_factory_( |
| 58 ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 68 ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
| 69 pac_request_(NULL), | |
| 70 tried_direct_connect_fallback_(false), | |
| 59 read_state_(IDLE), | 71 read_state_(IDLE), |
| 60 read_buf_(new net::IOBufferWithSize(read_buf_size)), | 72 read_buf_(new net::IOBufferWithSize(read_buf_size)), |
| 61 read_start_(0U), | 73 read_start_(0U), |
| 62 read_end_(0U), | 74 read_end_(0U), |
| 63 write_state_(IDLE), | 75 write_state_(IDLE), |
| 64 write_buf_(new net::IOBufferWithSize(write_buf_size)), | 76 write_buf_(new net::IOBufferWithSize(write_buf_size)), |
| 65 write_end_(0U) { | 77 write_end_(0U) { |
| 66 DCHECK(client_socket_factory_.get()); | 78 DCHECK(request_context_getter_.get()); |
| 67 DCHECK_GT(read_buf_size, 0U); | 79 DCHECK_GT(read_buf_size, 0U); |
| 68 DCHECK_GT(write_buf_size, 0U); | 80 DCHECK_GT(write_buf_size, 0U); |
| 81 net::HttpNetworkSession::Params session_params; | |
|
akalin
2011/04/13 20:49:32
It seems to me that you can at least construct the
sanjeevr
2011/04/13 21:20:21
This is also doable (though it is almost the same
| |
| 82 session_params.host_resolver = | |
| 83 request_context_getter_->GetURLRequestContext()->host_resolver(); | |
| 84 session_params.cert_verifier = | |
| 85 request_context_getter_->GetURLRequestContext()->cert_verifier(); | |
| 86 session_params.dnsrr_resolver = | |
| 87 request_context_getter_->GetURLRequestContext()->dnsrr_resolver(); | |
| 88 session_params.proxy_service = | |
| 89 request_context_getter_->GetURLRequestContext()->proxy_service(); | |
| 90 session_params.ssl_config_service = | |
| 91 request_context_getter_->GetURLRequestContext()->ssl_config_service(); | |
| 92 session_params.http_auth_handler_factory = | |
| 93 request_context_getter_->GetURLRequestContext()-> | |
| 94 http_auth_handler_factory(); | |
| 95 network_session_ = new net::HttpNetworkSession(session_params); | |
| 69 } | 96 } |
| 70 | 97 |
| 71 ChromeAsyncSocket::~ChromeAsyncSocket() {} | 98 ChromeAsyncSocket::~ChromeAsyncSocket() {} |
| 72 | 99 |
| 73 ChromeAsyncSocket::State ChromeAsyncSocket::state() { | 100 ChromeAsyncSocket::State ChromeAsyncSocket::state() { |
| 74 return state_; | 101 return state_; |
| 75 } | 102 } |
| 76 | 103 |
| 77 ChromeAsyncSocket::Error ChromeAsyncSocket::error() { | 104 ChromeAsyncSocket::Error ChromeAsyncSocket::error() { |
| 78 return error_; | 105 return error_; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 96 void ChromeAsyncSocket::DoNetError(net::Error net_error) { | 123 void ChromeAsyncSocket::DoNetError(net::Error net_error) { |
| 97 error_ = ERROR_WINSOCK; | 124 error_ = ERROR_WINSOCK; |
| 98 net_error_ = net_error; | 125 net_error_ = net_error; |
| 99 } | 126 } |
| 100 | 127 |
| 101 void ChromeAsyncSocket::DoNetErrorFromStatus(int status) { | 128 void ChromeAsyncSocket::DoNetErrorFromStatus(int status) { |
| 102 DCHECK_LT(status, net::OK); | 129 DCHECK_LT(status, net::OK); |
| 103 DoNetError(static_cast<net::Error>(status)); | 130 DoNetError(static_cast<net::Error>(status)); |
| 104 } | 131 } |
| 105 | 132 |
| 133 // STATE_CLOSED -> STATE_CONNECTING | |
| 134 bool ChromeAsyncSocket::Connect(const talk_base::SocketAddress& address) { | |
| 135 // Bypass for unit-tests. | |
| 136 if (client_socket_factory_.get()) | |
| 137 return ConnectUsingFactory(address); | |
| 138 | |
| 139 if (state_ != STATE_CLOSED) { | |
| 140 LOG(DFATAL) << "Connect() called on non-closed socket"; | |
| 141 DoNonNetError(ERROR_WRONGSTATE); | |
| 142 return false; | |
| 143 } | |
| 144 | |
| 145 // We can't work with an empty hostname and IP address. | |
| 146 if (address.hostname().empty() && (address.ip() == 0)) { | |
| 147 DoNonNetError(ERROR_DNS); | |
| 148 return false; | |
| 149 } | |
| 150 | |
| 151 | |
| 152 DCHECK_EQ(state_, buzz::AsyncSocket::STATE_CLOSED); | |
| 153 DCHECK_EQ(read_state_, IDLE); | |
| 154 DCHECK_EQ(write_state_, IDLE); | |
| 155 | |
| 156 state_ = STATE_CONNECTING; | |
| 157 | |
| 158 DCHECK(scoped_runnable_method_factory_.empty()); | |
| 159 scoped_runnable_method_factory_.RevokeAll(); | |
| 160 | |
| 161 // First we try and resolve the proxy. | |
| 162 dest_host_port_pair_ = | |
| 163 net::HostPortPair(address.IPAsString(), address.port()); | |
| 164 | |
| 165 GURL url = GURL("http://" + dest_host_port_pair_.ToString()); | |
| 166 int status = request_context_getter_->GetURLRequestContext()-> | |
| 167 proxy_service()->ResolveProxy(url, | |
| 168 &proxy_info_, | |
| 169 &proxy_resolve_callback_, | |
| 170 &pac_request_, | |
| 171 bound_net_log_); | |
| 172 if (status != net::ERR_IO_PENDING) { | |
| 173 ProcessProxyResolveDone(status); | |
| 174 } | |
| 175 return true; | |
| 176 } | |
| 177 | |
| 106 namespace { | 178 namespace { |
| 107 | 179 |
| 108 // Takes a 32-bit integer in host byte order and converts it to a | 180 // Takes a 32-bit integer in host byte order and converts it to a |
| 109 // net::IPAddressNumber. | 181 // net::IPAddressNumber. |
| 110 net::IPAddressNumber Uint32ToIPAddressNumber(uint32 ip) { | 182 net::IPAddressNumber Uint32ToIPAddressNumber(uint32 ip) { |
| 111 uint32 ip_nbo = htonl(ip); | 183 uint32 ip_nbo = htonl(ip); |
| 112 const unsigned char* const ip_start = | 184 const unsigned char* const ip_start = |
| 113 reinterpret_cast<const unsigned char*>(&ip_nbo); | 185 reinterpret_cast<const unsigned char*>(&ip_nbo); |
| 114 return net::IPAddressNumber(ip_start, ip_start + (sizeof ip_nbo)); | 186 return net::IPAddressNumber(ip_start, ip_start + (sizeof ip_nbo)); |
| 115 } | 187 } |
| 116 | 188 |
| 117 net::AddressList SocketAddressToAddressList( | 189 net::AddressList SocketAddressToAddressList( |
| 118 const talk_base::SocketAddress& address) { | 190 const talk_base::SocketAddress& address) { |
| 119 DCHECK_NE(address.ip(), 0U); | 191 DCHECK_NE(address.ip(), 0U); |
| 120 return net::AddressList(Uint32ToIPAddressNumber(address.ip()), | 192 return net::AddressList(Uint32ToIPAddressNumber(address.ip()), |
| 121 address.port(), false); | 193 address.port(), false); |
| 122 } | 194 } |
| 123 | 195 |
| 124 } // namespace | 196 } // namespace |
| 125 | 197 |
| 126 // STATE_CLOSED -> STATE_CONNECTING | 198 bool ChromeAsyncSocket::ConnectUsingFactory( |
| 127 | 199 const talk_base::SocketAddress& address) { |
| 128 bool ChromeAsyncSocket::Connect(const talk_base::SocketAddress& address) { | |
| 129 if (state_ != STATE_CLOSED) { | 200 if (state_ != STATE_CLOSED) { |
| 130 LOG(DFATAL) << "Connect() called on non-closed socket"; | 201 LOG(DFATAL) << "Connect() called on non-closed socket"; |
| 131 DoNonNetError(ERROR_WRONGSTATE); | 202 DoNonNetError(ERROR_WRONGSTATE); |
| 132 return false; | 203 return false; |
| 133 } | 204 } |
| 205 | |
| 134 if (address.ip() == 0) { | 206 if (address.ip() == 0) { |
| 135 DoNonNetError(ERROR_DNS); | 207 DoNonNetError(ERROR_DNS); |
| 136 return false; | 208 return false; |
| 137 } | 209 } |
| 138 | 210 |
| 139 DCHECK_EQ(state_, buzz::AsyncSocket::STATE_CLOSED); | 211 DCHECK_EQ(state_, buzz::AsyncSocket::STATE_CLOSED); |
| 140 DCHECK_EQ(read_state_, IDLE); | 212 DCHECK_EQ(read_state_, IDLE); |
| 141 DCHECK_EQ(write_state_, IDLE); | 213 DCHECK_EQ(write_state_, IDLE); |
| 142 | 214 |
| 143 state_ = STATE_CONNECTING; | 215 state_ = STATE_CONNECTING; |
| 144 | 216 |
| 145 DCHECK(scoped_runnable_method_factory_.empty()); | 217 DCHECK(scoped_runnable_method_factory_.empty()); |
| 146 scoped_runnable_method_factory_.RevokeAll(); | 218 scoped_runnable_method_factory_.RevokeAll(); |
| 147 | 219 |
| 148 net::AddressList address_list = SocketAddressToAddressList(address); | 220 net::AddressList address_list = SocketAddressToAddressList(address); |
| 149 transport_socket_.reset( | 221 net::ClientSocket* transport_socket = |
| 150 client_socket_factory_->CreateTransportClientSocket( | 222 client_socket_factory_->CreateTransportClientSocket( |
| 151 address_list, bound_net_log_.net_log(), net::NetLog::Source())); | 223 address_list, bound_net_log_.net_log(), net::NetLog::Source()); |
| 152 int status = transport_socket_->Connect(&connect_callback_); | 224 int status = transport_socket->Connect(&connect_callback_); |
| 225 connection_.reset(new net::ClientSocketHandle); | |
| 226 connection_->set_socket(transport_socket); | |
| 153 if (status != net::ERR_IO_PENDING) { | 227 if (status != net::ERR_IO_PENDING) { |
| 154 // We defer execution of ProcessConnectDone instead of calling it | 228 // We defer execution of ProcessConnectDone instead of calling it |
| 155 // directly here as the caller may not expect an error/close to | 229 // directly here as the caller may not expect an error/close to |
| 156 // happen here. This is okay, as from the caller's point of view, | 230 // happen here. This is okay, as from the caller's point of view, |
| 157 // the connect always happens asynchronously. | 231 // the connect always happens asynchronously. |
| 158 MessageLoop* message_loop = MessageLoop::current(); | 232 MessageLoop* message_loop = MessageLoop::current(); |
| 159 CHECK(message_loop); | 233 CHECK(message_loop); |
| 160 message_loop->PostTask( | 234 message_loop->PostTask( |
| 161 FROM_HERE, | 235 FROM_HERE, |
| 162 scoped_runnable_method_factory_.NewRunnableMethod( | 236 scoped_runnable_method_factory_.NewRunnableMethod( |
| 163 &ChromeAsyncSocket::ProcessConnectDone, status)); | 237 &ChromeAsyncSocket::ProcessConnectDone, status)); |
| 164 } | 238 } |
| 165 return true; | 239 return true; |
| 166 } | 240 } |
| 167 | 241 |
| 242 | |
| 243 void ChromeAsyncSocket::ProcessProxyResolveDone(int status) { | |
| 244 DCHECK_NE(status, net::ERR_IO_PENDING); | |
| 245 DCHECK_EQ(read_state_, IDLE); | |
| 246 DCHECK_EQ(write_state_, IDLE); | |
| 247 DCHECK_EQ(state_, STATE_CONNECTING); | |
| 248 if (status == net::OK) { | |
| 249 // Remove unsupported proxies from the list. | |
| 250 proxy_info_.RemoveProxiesWithoutScheme( | |
| 251 net::ProxyServer::SCHEME_DIRECT | | |
| 252 net::ProxyServer::SCHEME_HTTP | net::ProxyServer::SCHEME_HTTPS | | |
| 253 net::ProxyServer::SCHEME_SOCKS4 | net::ProxyServer::SCHEME_SOCKS5); | |
| 254 | |
| 255 if (proxy_info_.is_empty()) { | |
| 256 // No proxies/direct to choose from. This happens when we don't support | |
| 257 // any of the proxies in the returned list. | |
| 258 status = net::ERR_NO_SUPPORTED_PROXIES; | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 // Since we are faking the URL, it is possible that no proxies match our URL. | |
| 263 // Try falling back to a direct connection if we have not tried that before. | |
| 264 if (status != net::OK) { | |
| 265 if (!tried_direct_connect_fallback_) { | |
| 266 tried_direct_connect_fallback_ = true; | |
| 267 proxy_info_.UseDirect(); | |
| 268 } else { | |
| 269 DoNetErrorFromStatus(status); | |
| 270 DoClose(); | |
| 271 return; | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 connection_.reset(new net::ClientSocketHandle); | |
|
akalin
2011/04/13 20:49:32
Yeah this part is weird. Shouldn't we use a socke
sanjeevr
2011/04/13 21:20:21
We are not creating the socket ourselves. InitSock
| |
| 276 // Now that we have resolved the proxy, we need to connect. | |
| 277 status = net::ClientSocketPoolManager::InitSocketHandleForRawConnect( | |
| 278 dest_host_port_pair_, | |
| 279 network_session_.get(), | |
| 280 proxy_info_, | |
| 281 ssl_config_, | |
| 282 ssl_config_, | |
| 283 bound_net_log_, | |
| 284 connection_.get(), | |
| 285 &connect_callback_); | |
| 286 if (status != net::ERR_IO_PENDING) { | |
| 287 // We defer execution of ProcessConnectDone instead of calling it | |
| 288 // directly here as the caller may not expect an error/close to | |
| 289 // happen here. This is okay, as from the caller's point of view, | |
| 290 // the connect always happens asynchronously. | |
| 291 MessageLoop* message_loop = MessageLoop::current(); | |
| 292 CHECK(message_loop); | |
| 293 message_loop->PostTask( | |
| 294 FROM_HERE, | |
| 295 scoped_runnable_method_factory_.NewRunnableMethod( | |
| 296 &ChromeAsyncSocket::ProcessConnectDone, status)); | |
| 297 } | |
| 298 } | |
| 299 | |
| 168 // STATE_CONNECTING -> STATE_OPEN | 300 // STATE_CONNECTING -> STATE_OPEN |
| 169 // read_state_ == IDLE -> read_state_ == POSTED (via PostDoRead()) | 301 // read_state_ == IDLE -> read_state_ == POSTED (via PostDoRead()) |
| 170 | 302 |
| 171 void ChromeAsyncSocket::ProcessConnectDone(int status) { | 303 void ChromeAsyncSocket::ProcessConnectDone(int status) { |
| 172 DCHECK_NE(status, net::ERR_IO_PENDING); | 304 DCHECK_NE(status, net::ERR_IO_PENDING); |
| 173 DCHECK_EQ(read_state_, IDLE); | 305 DCHECK_EQ(read_state_, IDLE); |
| 174 DCHECK_EQ(write_state_, IDLE); | 306 DCHECK_EQ(write_state_, IDLE); |
| 175 DCHECK_EQ(state_, STATE_CONNECTING); | 307 DCHECK_EQ(state_, STATE_CONNECTING); |
| 176 if (status != net::OK) { | 308 if (status != net::OK) { |
| 309 // If the connection fails, try another proxy. | |
| 310 if (!client_socket_factory_.get()) | |
| 311 status = ReconsiderProxyAfterError(status); | |
| 312 if ((status != net::OK) && (status != net::ERR_IO_PENDING)) { | |
| 313 // If no more proxies to try, we are done. | |
| 314 DoNetErrorFromStatus(status); | |
| 315 DoClose(); | |
| 316 } | |
| 317 return; | |
| 318 } | |
| 319 // If we need to use a fake handshake, process that now. | |
| 320 if (use_fake_ssl_client_socket_) { | |
| 321 net::ClientSocket* fake_ssl_socket = | |
| 322 new FakeSSLClientSocket(connection_.release()); | |
| 323 connection_.reset(new net::ClientSocketHandle); | |
| 324 connection_->set_socket(fake_ssl_socket); | |
| 325 status = fake_ssl_socket->Connect(&fake_ssl_handshake_callback_); | |
| 326 if (status != net::ERR_IO_PENDING) | |
| 327 ProcessFakeSSLHandshakeDone(status); | |
| 328 } else { | |
| 329 state_ = STATE_OPEN; | |
| 330 PostDoRead(); | |
| 331 // Write buffer should be empty. | |
| 332 DCHECK_EQ(write_end_, 0U); | |
| 333 SignalConnected(); | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 // STATE_CONNECTING -> STATE_OPEN | |
| 338 // read_state_ == IDLE -> read_state_ == POSTED (via PostDoRead()) | |
| 339 | |
| 340 void ChromeAsyncSocket::ProcessFakeSSLHandshakeDone(int status) { | |
| 341 DCHECK_NE(status, net::ERR_IO_PENDING); | |
| 342 DCHECK_EQ(read_state_, IDLE); | |
| 343 DCHECK_EQ(write_state_, IDLE); | |
| 344 DCHECK_EQ(state_, STATE_CONNECTING); | |
| 345 if (status != net::OK) { | |
| 177 DoNetErrorFromStatus(status); | 346 DoNetErrorFromStatus(status); |
| 178 DoClose(); | 347 DoClose(); |
| 179 return; | 348 return; |
| 180 } | 349 } |
| 181 state_ = STATE_OPEN; | 350 state_ = STATE_OPEN; |
| 182 PostDoRead(); | 351 PostDoRead(); |
| 183 // Write buffer should be empty. | 352 // Write buffer should be empty. |
| 184 DCHECK_EQ(write_end_, 0U); | 353 DCHECK_EQ(write_end_, 0U); |
| 185 SignalConnected(); | 354 SignalConnected(); |
| 186 } | 355 } |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 205 | 374 |
| 206 void ChromeAsyncSocket::DoRead() { | 375 void ChromeAsyncSocket::DoRead() { |
| 207 DCHECK(IsOpen()); | 376 DCHECK(IsOpen()); |
| 208 DCHECK_EQ(read_state_, POSTED); | 377 DCHECK_EQ(read_state_, POSTED); |
| 209 DCHECK_EQ(read_start_, 0U); | 378 DCHECK_EQ(read_start_, 0U); |
| 210 DCHECK_EQ(read_end_, 0U); | 379 DCHECK_EQ(read_end_, 0U); |
| 211 // Once we call Read(), we cannot call StartTls() until the read | 380 // Once we call Read(), we cannot call StartTls() until the read |
| 212 // finishes. This is okay, as StartTls() is called only from a read | 381 // finishes. This is okay, as StartTls() is called only from a read |
| 213 // handler (i.e., after a read finishes and before another read is | 382 // handler (i.e., after a read finishes and before another read is |
| 214 // done). | 383 // done). |
| 215 int status = | 384 int status = connection_->socket()->Read( |
| 216 transport_socket_->Read( | 385 read_buf_.get(), read_buf_->size(), &read_callback_); |
| 217 read_buf_.get(), read_buf_->size(), &read_callback_); | |
| 218 read_state_ = PENDING; | 386 read_state_ = PENDING; |
| 219 if (status != net::ERR_IO_PENDING) { | 387 if (status != net::ERR_IO_PENDING) { |
| 220 ProcessReadDone(status); | 388 ProcessReadDone(status); |
| 221 } | 389 } |
| 222 } | 390 } |
| 223 | 391 |
| 224 // read_state_ == PENDING -> read_state_ == IDLE | 392 // read_state_ == PENDING -> read_state_ == IDLE |
| 225 | 393 |
| 226 void ChromeAsyncSocket::ProcessReadDone(int status) { | 394 void ChromeAsyncSocket::ProcessReadDone(int status) { |
| 227 DCHECK_NE(status, net::ERR_IO_PENDING); | 395 DCHECK_NE(status, net::ERR_IO_PENDING); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 336 // write_state_ == POSTED -> write_state_ == PENDING | 504 // write_state_ == POSTED -> write_state_ == PENDING |
| 337 | 505 |
| 338 void ChromeAsyncSocket::DoWrite() { | 506 void ChromeAsyncSocket::DoWrite() { |
| 339 DCHECK(IsOpen()); | 507 DCHECK(IsOpen()); |
| 340 DCHECK_EQ(write_state_, POSTED); | 508 DCHECK_EQ(write_state_, POSTED); |
| 341 DCHECK_GT(write_end_, 0U); | 509 DCHECK_GT(write_end_, 0U); |
| 342 // Once we call Write(), we cannot call StartTls() until the write | 510 // Once we call Write(), we cannot call StartTls() until the write |
| 343 // finishes. This is okay, as StartTls() is called only after we | 511 // finishes. This is okay, as StartTls() is called only after we |
| 344 // have received a reply to a message we sent to the server and | 512 // have received a reply to a message we sent to the server and |
| 345 // before we send the next message. | 513 // before we send the next message. |
| 346 int status = | 514 int status = connection_->socket()->Write( |
| 347 transport_socket_->Write( | 515 write_buf_.get(), write_end_, &write_callback_); |
| 348 write_buf_.get(), write_end_, &write_callback_); | |
| 349 write_state_ = PENDING; | 516 write_state_ = PENDING; |
| 350 if (status != net::ERR_IO_PENDING) { | 517 if (status != net::ERR_IO_PENDING) { |
| 351 ProcessWriteDone(status); | 518 ProcessWriteDone(status); |
| 352 } | 519 } |
| 353 } | 520 } |
| 354 | 521 |
| 355 // write_state_ == PENDING -> write_state_ == IDLE or POSTED (the | 522 // write_state_ == PENDING -> write_state_ == IDLE or POSTED (the |
| 356 // latter via PostDoWrite()) | 523 // latter via PostDoWrite()) |
| 357 | 524 |
| 358 void ChromeAsyncSocket::ProcessWriteDone(int status) { | 525 void ChromeAsyncSocket::ProcessWriteDone(int status) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 390 | 557 |
| 391 bool ChromeAsyncSocket::Close() { | 558 bool ChromeAsyncSocket::Close() { |
| 392 DoClose(); | 559 DoClose(); |
| 393 return true; | 560 return true; |
| 394 } | 561 } |
| 395 | 562 |
| 396 // (not STATE_CLOSED) -> STATE_CLOSED | 563 // (not STATE_CLOSED) -> STATE_CLOSED |
| 397 | 564 |
| 398 void ChromeAsyncSocket::DoClose() { | 565 void ChromeAsyncSocket::DoClose() { |
| 399 scoped_runnable_method_factory_.RevokeAll(); | 566 scoped_runnable_method_factory_.RevokeAll(); |
| 400 if (transport_socket_.get()) { | 567 // Disconnect the socket. |
| 401 transport_socket_->Disconnect(); | 568 if (connection_.get() && connection_->socket()) |
| 402 } | 569 connection_->socket()->Disconnect(); |
| 403 transport_socket_.reset(); | 570 connection_.reset(); |
| 404 read_state_ = IDLE; | 571 read_state_ = IDLE; |
| 405 read_start_ = 0U; | 572 read_start_ = 0U; |
| 406 read_end_ = 0U; | 573 read_end_ = 0U; |
| 407 write_state_ = IDLE; | 574 write_state_ = IDLE; |
| 408 write_end_ = 0U; | 575 write_end_ = 0U; |
| 409 if (state_ != STATE_CLOSED) { | 576 if (state_ != STATE_CLOSED) { |
| 410 state_ = STATE_CLOSED; | 577 state_ = STATE_CLOSED; |
| 411 SignalClosed(); | 578 SignalClosed(); |
| 412 } | 579 } |
| 413 // Reset error variables after SignalClosed() so slots connected | 580 // Reset error variables after SignalClosed() so slots connected |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 428 | 595 |
| 429 state_ = STATE_TLS_CONNECTING; | 596 state_ = STATE_TLS_CONNECTING; |
| 430 read_state_ = IDLE; | 597 read_state_ = IDLE; |
| 431 read_start_ = 0U; | 598 read_start_ = 0U; |
| 432 read_end_ = 0U; | 599 read_end_ = 0U; |
| 433 DCHECK_EQ(write_end_, 0U); | 600 DCHECK_EQ(write_end_, 0U); |
| 434 | 601 |
| 435 // Clear out any posted DoRead() tasks. | 602 // Clear out any posted DoRead() tasks. |
| 436 scoped_runnable_method_factory_.RevokeAll(); | 603 scoped_runnable_method_factory_.RevokeAll(); |
| 437 | 604 |
| 438 DCHECK(transport_socket_.get()); | 605 net::ClientSocketFactory* factory = |
| 439 transport_socket_.reset( | 606 client_socket_factory_.get() ? client_socket_factory_.get() |
| 440 client_socket_factory_->CreateSSLClientSocket( | 607 : net::ClientSocketFactory::GetDefaultFactory(); |
| 441 transport_socket_.release(), net::HostPortPair(domain_name, 443), | 608 |
| 442 ssl_config_, NULL /* ssl_host_info */, | 609 DCHECK(connection_.get()); |
| 443 cert_verifier_)); | 610 net::ClientSocket* ssl_socket = factory->CreateSSLClientSocket( |
| 444 int status = transport_socket_->Connect(&ssl_connect_callback_); | 611 connection_.release(), net::HostPortPair(domain_name, 443), |
| 612 ssl_config_, NULL /* ssl_host_info */, | |
| 613 request_context_getter_->GetURLRequestContext()->cert_verifier(), | |
| 614 NULL); | |
| 615 connection_.reset(new net::ClientSocketHandle); | |
| 616 connection_->set_socket(ssl_socket); | |
| 617 | |
| 618 int status = ssl_socket->Connect(&ssl_connect_callback_); | |
| 445 if (status != net::ERR_IO_PENDING) { | 619 if (status != net::ERR_IO_PENDING) { |
| 446 MessageLoop* message_loop = MessageLoop::current(); | 620 MessageLoop* message_loop = MessageLoop::current(); |
| 447 CHECK(message_loop); | 621 CHECK(message_loop); |
| 448 message_loop->PostTask( | 622 message_loop->PostTask( |
| 449 FROM_HERE, | 623 FROM_HERE, |
| 450 scoped_runnable_method_factory_.NewRunnableMethod( | 624 scoped_runnable_method_factory_.NewRunnableMethod( |
| 451 &ChromeAsyncSocket::ProcessSSLConnectDone, status)); | 625 &ChromeAsyncSocket::ProcessSSLConnectDone, status)); |
| 452 } | 626 } |
| 453 return true; | 627 return true; |
| 454 } | 628 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 471 return; | 645 return; |
| 472 } | 646 } |
| 473 state_ = STATE_TLS_OPEN; | 647 state_ = STATE_TLS_OPEN; |
| 474 PostDoRead(); | 648 PostDoRead(); |
| 475 if (write_end_ > 0U) { | 649 if (write_end_ > 0U) { |
| 476 PostDoWrite(); | 650 PostDoWrite(); |
| 477 } | 651 } |
| 478 SignalSSLConnected(); | 652 SignalSSLConnected(); |
| 479 } | 653 } |
| 480 | 654 |
| 655 // TODO(sanjeevr): This has largely been copied from | |
| 656 // HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError. This should be | |
| 657 // refactored into some common place. | |
| 658 int ChromeAsyncSocket::ReconsiderProxyAfterError(int error) { | |
| 659 DCHECK(!pac_request_); | |
| 660 // A failure to resolve the hostname or any error related to establishing a | |
| 661 // TCP connection could be grounds for trying a new proxy configuration. | |
| 662 // | |
| 663 // Why do this when a hostname cannot be resolved? Some URLs only make sense | |
| 664 // to proxy servers. The hostname in those URLs might fail to resolve if we | |
| 665 // are still using a non-proxy config. We need to check if a proxy config | |
| 666 // now exists that corresponds to a proxy server that could load the URL. | |
| 667 // | |
| 668 switch (error) { | |
| 669 case net::ERR_PROXY_CONNECTION_FAILED: | |
| 670 case net::ERR_NAME_NOT_RESOLVED: | |
| 671 case net::ERR_INTERNET_DISCONNECTED: | |
| 672 case net::ERR_ADDRESS_UNREACHABLE: | |
| 673 case net::ERR_CONNECTION_CLOSED: | |
| 674 case net::ERR_CONNECTION_RESET: | |
| 675 case net::ERR_CONNECTION_REFUSED: | |
| 676 case net::ERR_CONNECTION_ABORTED: | |
| 677 case net::ERR_TIMED_OUT: | |
| 678 case net::ERR_TUNNEL_CONNECTION_FAILED: | |
| 679 case net::ERR_SOCKS_CONNECTION_FAILED: | |
| 680 break; | |
| 681 case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: | |
| 682 // Remap the SOCKS-specific "host unreachable" error to a more | |
| 683 // generic error code (this way consumers like the link doctor | |
| 684 // know to substitute their error page). | |
| 685 // | |
| 686 // Note that if the host resolving was done by the SOCSK5 proxy, we can't | |
| 687 // differentiate between a proxy-side "host not found" versus a proxy-side | |
| 688 // "address unreachable" error, and will report both of these failures as | |
| 689 // ERR_ADDRESS_UNREACHABLE. | |
| 690 return net::ERR_ADDRESS_UNREACHABLE; | |
| 691 default: | |
| 692 return error; | |
| 693 } | |
| 694 | |
| 695 if (proxy_info_.is_https() && ssl_config_.send_client_cert) { | |
| 696 network_session_->ssl_client_auth_cache()->Remove( | |
| 697 proxy_info_.proxy_server().host_port_pair().ToString()); | |
| 698 } | |
| 699 | |
| 700 GURL url = GURL("http://" + dest_host_port_pair_.ToString()); | |
| 701 int rv = network_session_->proxy_service()->ReconsiderProxyAfterError( | |
| 702 url, &proxy_info_, &proxy_resolve_callback_, &pac_request_, | |
| 703 bound_net_log_); | |
| 704 if (rv == net::OK || rv == net::ERR_IO_PENDING) { | |
| 705 // If the error was during connection setup, there is no socket to | |
| 706 // disconnect. | |
| 707 if (connection_->socket()) | |
| 708 connection_->socket()->Disconnect(); | |
| 709 connection_->Reset(); | |
| 710 } else { | |
| 711 // If ReconsiderProxyAfterError() failed synchronously, it means | |
| 712 // there was nothing left to fall-back to, so fail the transaction | |
| 713 // with the last connection error we got. | |
| 714 rv = error; | |
| 715 } | |
| 716 | |
| 717 // We either have new proxy info or there was an error in falling back. | |
| 718 // In both cases we want to post ProcessProxyResolveDone (in the error case | |
| 719 // we might still want to fall back a direct connection). | |
| 720 if (rv != net::ERR_IO_PENDING) { | |
| 721 MessageLoop* message_loop = MessageLoop::current(); | |
| 722 CHECK(message_loop); | |
| 723 message_loop->PostTask( | |
| 724 FROM_HERE, | |
| 725 scoped_runnable_method_factory_.NewRunnableMethod( | |
| 726 &ChromeAsyncSocket::ProcessProxyResolveDone, rv)); | |
| 727 } | |
| 728 return rv; | |
| 729 } | |
| 730 | |
| 481 } // namespace notifier | 731 } // namespace notifier |
| OLD | NEW |