Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "net/socket/tcp_client_socket.h" | 5 #include "net/socket/tcp_client_socket.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 9 | 9 |
| 10 #if defined(OS_WIN) | |
|
wtc
2013/09/06 21:55:42
No need to add #if defined(OS_WIN) because these h
yzshen1
2013/09/09 23:14:48
Done.
| |
| 11 | |
| 12 #include "net/base/io_buffer.h" | |
| 13 #include "net/base/ip_endpoint.h" | |
| 14 #include "net/base/net_errors.h" | |
| 15 #include "net/base/net_util.h" | |
| 16 | |
| 17 #endif | |
| 18 | |
| 10 namespace net { | 19 namespace net { |
| 11 | 20 |
| 12 namespace { | 21 namespace { |
| 13 | 22 |
| 14 #if defined(OS_LINUX) | 23 #if defined(OS_LINUX) |
| 15 | 24 |
| 16 // Checks to see if the system supports TCP FastOpen. Notably, it requires | 25 // Checks to see if the system supports TCP FastOpen. Notably, it requires |
| 17 // kernel support. Additionally, this checks system configuration to ensure that | 26 // kernel support. Additionally, this checks system configuration to ensure that |
| 18 // it's enabled. | 27 // it's enabled. |
| 19 bool SystemSupportsTCPFastOpen() { | 28 bool SystemSupportsTCPFastOpen() { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 49 static bool g_tcp_fastopen_enabled = false; | 58 static bool g_tcp_fastopen_enabled = false; |
| 50 | 59 |
| 51 void SetTCPFastOpenEnabled(bool value) { | 60 void SetTCPFastOpenEnabled(bool value) { |
| 52 g_tcp_fastopen_enabled = value && SystemSupportsTCPFastOpen(); | 61 g_tcp_fastopen_enabled = value && SystemSupportsTCPFastOpen(); |
| 53 } | 62 } |
| 54 | 63 |
| 55 bool IsTCPFastOpenEnabled() { | 64 bool IsTCPFastOpenEnabled() { |
| 56 return g_tcp_fastopen_enabled; | 65 return g_tcp_fastopen_enabled; |
| 57 } | 66 } |
| 58 | 67 |
| 68 #if defined(OS_WIN) | |
| 69 | |
| 70 TCPClientSocket::TCPClientSocket(const AddressList& addresses, | |
| 71 net::NetLog* net_log, | |
| 72 const net::NetLog::Source& source) | |
| 73 : socket_(new TCPSocket(net_log, source)), | |
| 74 addresses_(addresses), | |
| 75 current_address_index_(-1), | |
| 76 next_connect_state_(CONNECT_STATE_NONE), | |
| 77 previously_disconnected_(false) { | |
| 78 } | |
| 79 | |
| 80 TCPClientSocket::TCPClientSocket(scoped_ptr<TCPSocket> connected_socket, | |
| 81 const IPEndPoint& peer_address) | |
| 82 : socket_(connected_socket.Pass()), | |
| 83 addresses_(AddressList(peer_address)), | |
| 84 current_address_index_(0), | |
| 85 next_connect_state_(CONNECT_STATE_NONE), | |
| 86 previously_disconnected_(false) { | |
| 87 DCHECK(socket_.get()); | |
|
akalin
2013/09/05 22:52:28
no need for .get()
yzshen1
2013/09/06 00:57:44
Done.
| |
| 88 | |
| 89 int result = socket_->SetDefaultOptionsForClient(); | |
|
wtc
2013/09/06 21:55:42
This should have been called when the passed-in TC
yzshen1
2013/09/09 23:14:48
Please see my comments below at line 362.
On 201
| |
| 90 if (result != OK) | |
| 91 PLOG(ERROR) << "TCPSocket::SetDefaultOptionsForClient() returned an error"; | |
|
akalin
2013/09/05 22:52:28
this is unfortunate. Do we really want to swallow
yzshen1
2013/09/06 00:57:44
I think this is not a fatal issue, maybe we can sw
akalin
2013/09/12 23:21:37
Seems like a good reason to just make SetDefaultOp
yzshen1
2013/09/13 05:07:51
Done.
| |
| 92 | |
| 93 use_history_.set_was_ever_connected(); | |
| 94 } | |
| 95 | |
| 96 TCPClientSocket::~TCPClientSocket() { | |
| 97 } | |
| 98 | |
| 99 int TCPClientSocket::Bind(const IPEndPoint& address) { | |
| 100 if (current_address_index_ >= 0 || bind_address_.get()) { | |
|
akalin
2013/09/05 22:52:28
no .get()
yzshen1
2013/09/06 00:57:44
Done.
| |
| 101 // Cannot bind the socket if we are already connected or connecting. | |
| 102 return ERR_UNEXPECTED; | |
|
akalin
2013/09/05 22:52:28
ERR_UNEXPECTED is usually found with NOTREACHED()
yzshen1
2013/09/06 00:57:44
Done.
| |
| 103 } | |
| 104 | |
| 105 int result = OK; | |
| 106 if (!socket_->IsValid()) { | |
| 107 result = CreateSocket(address.GetFamily()); | |
| 108 if (result != OK) | |
| 109 return result; | |
| 110 } | |
| 111 | |
| 112 result = socket_->Bind(address); | |
| 113 if (result != OK) | |
| 114 return result; | |
| 115 | |
| 116 bind_address_.reset(new IPEndPoint(address)); | |
| 117 return OK; | |
| 118 } | |
| 119 | |
| 120 int TCPClientSocket::Connect(const CompletionCallback& callback) { | |
| 121 DCHECK(!callback.is_null()); | |
| 122 | |
| 123 // If connecting or already connected, then just return OK. | |
| 124 if (socket_->IsValid() && current_address_index_ >= 0) | |
| 125 return OK; | |
| 126 | |
| 127 socket_->StartLoggingMultipleConnectAttempts(addresses_); | |
| 128 | |
| 129 // We will try to connect to each address in addresses_. Start with the | |
| 130 // first one in the list. | |
| 131 next_connect_state_ = CONNECT_STATE_CONNECT; | |
| 132 current_address_index_ = 0; | |
| 133 | |
| 134 int rv = DoConnectLoop(OK); | |
| 135 if (rv == ERR_IO_PENDING) { | |
| 136 connect_callback_ = callback; | |
| 137 } else { | |
| 138 socket_->EndLoggingMultipleConnectAttempts(rv); | |
| 139 } | |
| 140 | |
| 141 return rv; | |
| 142 } | |
| 143 | |
| 144 int TCPClientSocket::DoConnectLoop(int result) { | |
| 145 DCHECK_NE(next_connect_state_, CONNECT_STATE_NONE); | |
| 146 | |
| 147 int rv = result; | |
| 148 do { | |
| 149 ConnectState state = next_connect_state_; | |
| 150 next_connect_state_ = CONNECT_STATE_NONE; | |
| 151 switch (state) { | |
| 152 case CONNECT_STATE_CONNECT: | |
| 153 DCHECK_EQ(OK, rv); | |
| 154 rv = DoConnect(); | |
| 155 break; | |
| 156 case CONNECT_STATE_CONNECT_COMPLETE: | |
| 157 rv = DoConnectComplete(rv); | |
| 158 break; | |
| 159 default: | |
| 160 LOG(DFATAL) << "bad state " << state; | |
|
akalin
2013/09/05 22:52:28
NOTREACHED() instead of LOG(DFATAL)? (They're equi
yzshen1
2013/09/06 00:57:44
Done.
| |
| 161 rv = ERR_UNEXPECTED; | |
| 162 break; | |
| 163 } | |
| 164 } while (rv != ERR_IO_PENDING && next_connect_state_ != CONNECT_STATE_NONE); | |
| 165 | |
| 166 return rv; | |
| 167 } | |
| 168 | |
| 169 int TCPClientSocket::DoConnect() { | |
| 170 DCHECK_GE(current_address_index_, 0); | |
| 171 DCHECK_LT(current_address_index_, static_cast<int>(addresses_.size())); | |
| 172 | |
| 173 const IPEndPoint& endpoint = addresses_[current_address_index_]; | |
| 174 | |
| 175 if (previously_disconnected_) { | |
| 176 use_history_.Reset(); | |
| 177 previously_disconnected_ = false; | |
| 178 } | |
| 179 | |
| 180 next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE; | |
| 181 | |
| 182 if (socket_->IsValid()) { | |
| 183 DCHECK(bind_address_.get()); | |
|
akalin
2013/09/05 22:52:28
no .get() (also everywhere else)
yzshen1
2013/09/06 00:57:44
Done. Also changed other places.
| |
| 184 } else { | |
| 185 int result = CreateSocket(endpoint.GetFamily()); | |
| 186 if (result != OK) | |
| 187 return result; | |
| 188 | |
| 189 if (bind_address_.get()) { | |
| 190 result = socket_->Bind(*bind_address_); | |
| 191 if (result != OK) { | |
| 192 socket_->Close(); | |
| 193 return result; | |
| 194 } | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 return socket_->Connect(endpoint, | |
| 199 base::Bind(&TCPClientSocket::DidCompleteConnect, | |
| 200 base::Unretained(this))); | |
| 201 } | |
| 202 | |
| 203 int TCPClientSocket::DoConnectComplete(int result) { | |
| 204 if (result == OK) { | |
| 205 use_history_.set_was_ever_connected(); | |
| 206 return OK; // Done! | |
| 207 } | |
| 208 | |
| 209 // Close whatever partially connected socket we currently have. | |
| 210 DoDisconnect(); | |
| 211 | |
| 212 // Try to fall back to the next address in the list. | |
| 213 if (current_address_index_ + 1 < static_cast<int>(addresses_.size())) { | |
| 214 next_connect_state_ = CONNECT_STATE_CONNECT; | |
| 215 ++current_address_index_; | |
| 216 return OK; | |
| 217 } | |
| 218 | |
| 219 // Otherwise there is nothing to fall back to, so give up. | |
| 220 return result; | |
| 221 } | |
| 222 | |
| 223 void TCPClientSocket::Disconnect() { | |
| 224 DoDisconnect(); | |
| 225 current_address_index_ = -1; | |
| 226 bind_address_.reset(); | |
| 227 } | |
| 228 | |
| 229 void TCPClientSocket::DoDisconnect() { | |
| 230 // If connecting or already connected, record that the socket has been | |
| 231 // disconnected. | |
| 232 previously_disconnected_ = socket_->IsValid() && current_address_index_ >= 0; | |
| 233 socket_->Close(); | |
| 234 } | |
| 235 | |
| 236 bool TCPClientSocket::IsConnected() const { | |
| 237 return socket_->IsConnected(); | |
| 238 } | |
| 239 | |
| 240 bool TCPClientSocket::IsConnectedAndIdle() const { | |
| 241 return socket_->IsConnectedAndIdle(); | |
| 242 } | |
| 243 | |
| 244 int TCPClientSocket::GetPeerAddress(IPEndPoint* address) const { | |
| 245 return socket_->GetPeerAddress(address); | |
| 246 } | |
| 247 | |
| 248 int TCPClientSocket::GetLocalAddress(IPEndPoint* address) const { | |
| 249 DCHECK(address); | |
| 250 | |
| 251 if (!socket_->IsValid()) { | |
| 252 if (bind_address_.get()) { | |
| 253 *address = *bind_address_; | |
| 254 return OK; | |
| 255 } | |
| 256 return ERR_SOCKET_NOT_CONNECTED; | |
| 257 } | |
| 258 | |
| 259 return socket_->GetLocalAddress(address); | |
| 260 } | |
| 261 | |
| 262 void TCPClientSocket::SetSubresourceSpeculation() { | |
| 263 use_history_.set_subresource_speculation(); | |
| 264 } | |
| 265 | |
| 266 void TCPClientSocket::SetOmniboxSpeculation() { | |
| 267 use_history_.set_omnibox_speculation(); | |
| 268 } | |
| 269 | |
| 270 bool TCPClientSocket::WasEverUsed() const { | |
| 271 return use_history_.was_used_to_convey_data(); | |
| 272 } | |
| 273 | |
| 274 bool TCPClientSocket::UsingTCPFastOpen() const { | |
| 275 return socket_->UsingTCPFastOpen(); | |
| 276 } | |
| 277 | |
| 278 bool TCPClientSocket::WasNpnNegotiated() const { | |
| 279 return false; | |
| 280 } | |
| 281 | |
| 282 NextProto TCPClientSocket::GetNegotiatedProtocol() const { | |
| 283 return kProtoUnknown; | |
| 284 } | |
| 285 | |
| 286 bool TCPClientSocket::GetSSLInfo(SSLInfo* ssl_info) { | |
| 287 return false; | |
| 288 } | |
| 289 | |
| 290 int TCPClientSocket::Read(IOBuffer* buf, | |
| 291 int buf_len, | |
| 292 const CompletionCallback& callback) { | |
| 293 DCHECK(!callback.is_null()); | |
| 294 | |
| 295 CompletionCallback read_callback = base::Bind( | |
| 296 &TCPClientSocket::DidCompleteReadWrite, base::Unretained(this), callback); | |
|
akalin
2013/09/05 22:52:28
comment as to why Unretained() can be used safely
yzshen1
2013/09/06 00:57:44
Done.
| |
| 297 int result = socket_->Read(buf, buf_len, read_callback); | |
| 298 if (result > 0) | |
| 299 use_history_.set_was_used_to_convey_data(); | |
| 300 | |
| 301 return result; | |
| 302 } | |
| 303 | |
| 304 int TCPClientSocket::Write(IOBuffer* buf, | |
| 305 int buf_len, | |
| 306 const CompletionCallback& callback) { | |
| 307 DCHECK(!callback.is_null()); | |
| 308 | |
| 309 CompletionCallback write_callback = base::Bind( | |
| 310 &TCPClientSocket::DidCompleteReadWrite, base::Unretained(this), callback); | |
| 311 int result = socket_->Write(buf, buf_len, write_callback); | |
| 312 if (result > 0) | |
| 313 use_history_.set_was_used_to_convey_data(); | |
| 314 | |
| 315 return result; | |
| 316 } | |
| 317 | |
| 318 bool TCPClientSocket::SetReceiveBufferSize(int32 size) { | |
| 319 return socket_->SetReceiveBufferSize(size); | |
| 320 } | |
| 321 | |
| 322 bool TCPClientSocket::SetSendBufferSize(int32 size) { | |
| 323 return socket_->SetSendBufferSize(size); | |
| 324 } | |
| 325 | |
| 326 bool TCPClientSocket::SetKeepAlive(bool enable, int delay) { | |
| 327 return socket_->SetKeepAlive(enable, delay); | |
| 328 } | |
| 329 | |
| 330 bool TCPClientSocket::SetNoDelay(bool no_delay) { | |
| 331 return socket_->SetNoDelay(no_delay); | |
| 332 } | |
| 333 | |
| 334 void TCPClientSocket::DidCompleteConnect(int result) { | |
| 335 DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE); | |
|
wtc
2013/09/06 21:55:42
You can also DCHECK these:
DCHECK_NE(result, ER
yzshen1
2013/09/09 23:14:48
Done.
| |
| 336 | |
| 337 result = DoConnectLoop(result); | |
| 338 if (result != ERR_IO_PENDING) { | |
| 339 socket_->EndLoggingMultipleConnectAttempts(result); | |
| 340 CompletionCallback callback = connect_callback_; | |
| 341 connect_callback_.Reset(); | |
| 342 callback.Run(result); | |
|
wtc
2013/09/06 21:55:42
I remember there is a new CompletionCallback metho
yzshen1
2013/09/09 23:14:48
Done.
| |
| 343 } | |
| 344 } | |
| 345 | |
| 346 void TCPClientSocket::DidCompleteReadWrite( | |
| 347 const CompletionCallback& forward_callback, | |
|
wtc
2013/09/06 21:55:42
Why is this argument named "forward_callback"? Why
yzshen1
2013/09/09 23:14:48
Done.
| |
| 348 int result) { | |
| 349 if (result > 0) | |
| 350 use_history_.set_was_used_to_convey_data(); | |
| 351 | |
| 352 forward_callback.Run(result); | |
| 353 } | |
| 354 | |
| 355 int TCPClientSocket::CreateSocket(AddressFamily family) { | |
| 356 DCHECK(!socket_->IsValid()); | |
| 357 | |
| 358 int result = socket_->Create(family); | |
| 359 if (result != OK) | |
| 360 return result; | |
| 361 | |
| 362 result = socket_->SetDefaultOptionsForClient(); | |
|
wtc
2013/09/06 21:55:42
SetDefaultOptionsForClient can be called by TCPSoc
yzshen1
2013/09/09 23:14:48
IMO, this seems to cause inconsistency: Do we also
wtc
2013/09/12 01:27:16
Another idea is to just call SetDefaultOptionsForC
yzshen1
2013/09/12 20:07:50
Thanks! I will leave it as it is.
| |
| 363 if (result != OK) | |
| 364 socket_->Close(); | |
| 365 | |
| 366 return result; | |
| 367 } | |
| 368 | |
| 369 #endif | |
| 370 | |
| 59 } // namespace net | 371 } // namespace net |
| OLD | NEW |