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