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 |