1 // Copyright 2014 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.
5 #include "net/socket/websocket_transport_connect_sub_job.h"
7 #include "base/logging.h"
8 #include "net/base/ip_endpoint.h"
9 #include "net/base/net_errors.h"
10 #include "net/base/net_log.h"
11 #include "net/socket/client_socket_factory.h"
12 #include "net/socket/websocket_endpoint_lock_manager.h"
16 WebSocketTransportConnectSubJob::WebSocketTransportConnectSubJob(
17 const AddressList
& addresses
,
18 WebSocketTransportConnectJob
* parent_job
,
20 : parent_job_(parent_job
),
21 addresses_(addresses
),
22 current_address_index_(0),
23 next_state_(STATE_NONE
),
26 WebSocketTransportConnectSubJob::~WebSocketTransportConnectSubJob() {
27 // We don't worry about cancelling the TCP connect, since ~StreamSocket will
30 DCHECK_EQ(STATE_OBTAIN_LOCK_COMPLETE
, next_state_
);
31 // The ~Waiter destructor will remove this object from the waiting list.
32 } else if (next_state_
== STATE_TRANSPORT_CONNECT_COMPLETE
) {
33 WebSocketEndpointLockManager::GetInstance()->UnlockEndpoint(
39 int WebSocketTransportConnectSubJob::Start() {
40 DCHECK_EQ(STATE_NONE
, next_state_
);
41 next_state_
= STATE_OBTAIN_LOCK
;
45 // Called by WebSocketEndpointLockManager when the lock becomes available.
46 void WebSocketTransportConnectSubJob::GotEndpointLock() {
47 DCHECK_EQ(STATE_OBTAIN_LOCK_COMPLETE
, next_state_
);
51 LoadState
WebSocketTransportConnectSubJob::GetLoadState() const {
52 switch (next_state_
) {
53 case STATE_OBTAIN_LOCK
:
54 case STATE_OBTAIN_LOCK_COMPLETE
:
55 // TODO(ricea): Add a WebSocket-specific LOAD_STATE ?
56 return LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET
;
57 case STATE_TRANSPORT_CONNECT
:
58 case STATE_TRANSPORT_CONNECT_COMPLETE
:
60 return LOAD_STATE_CONNECTING
;
62 return LOAD_STATE_IDLE
;
65 return LOAD_STATE_IDLE
;
68 ClientSocketFactory
* WebSocketTransportConnectSubJob::client_socket_factory()
70 return parent_job_
->helper_
.client_socket_factory();
73 const BoundNetLog
& WebSocketTransportConnectSubJob::net_log() const {
74 return parent_job_
->net_log();
77 const IPEndPoint
& WebSocketTransportConnectSubJob::CurrentAddress() const {
78 DCHECK_LT(current_address_index_
, addresses_
.size());
79 return addresses_
[current_address_index_
];
82 void WebSocketTransportConnectSubJob::OnIOComplete(int result
) {
83 int rv
= DoLoop(result
);
84 if (rv
!= ERR_IO_PENDING
)
85 parent_job_
->OnSubJobComplete(rv
, this); // |this| deleted
88 int WebSocketTransportConnectSubJob::DoLoop(int result
) {
89 DCHECK_NE(next_state_
, STATE_NONE
);
93 State state
= next_state_
;
94 next_state_
= STATE_NONE
;
96 case STATE_OBTAIN_LOCK
:
98 rv
= DoEndpointLock();
100 case STATE_OBTAIN_LOCK_COMPLETE
:
102 rv
= DoEndpointLockComplete();
104 case STATE_TRANSPORT_CONNECT
:
106 rv
= DoTransportConnect();
108 case STATE_TRANSPORT_CONNECT_COMPLETE
:
109 rv
= DoTransportConnectComplete(rv
);
116 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
&&
117 next_state_
!= STATE_DONE
);
122 int WebSocketTransportConnectSubJob::DoEndpointLock() {
123 int rv
= WebSocketEndpointLockManager::GetInstance()->LockEndpoint(
124 CurrentAddress(), this);
125 next_state_
= STATE_OBTAIN_LOCK_COMPLETE
;
129 int WebSocketTransportConnectSubJob::DoEndpointLockComplete() {
130 next_state_
= STATE_TRANSPORT_CONNECT
;
134 int WebSocketTransportConnectSubJob::DoTransportConnect() {
135 // TODO(ricea): Update global g_last_connect_time and report
137 next_state_
= STATE_TRANSPORT_CONNECT_COMPLETE
;
138 AddressList
one_address(CurrentAddress());
139 transport_socket_
= client_socket_factory()->CreateTransportClientSocket(
140 one_address
, net_log().net_log(), net_log().source());
141 // This use of base::Unretained() is safe because transport_socket_ is
142 // destroyed in the destructor.
143 return transport_socket_
->Connect(base::Bind(
144 &WebSocketTransportConnectSubJob::OnIOComplete
, base::Unretained(this)));
147 int WebSocketTransportConnectSubJob::DoTransportConnectComplete(int result
) {
148 next_state_
= STATE_DONE
;
149 WebSocketEndpointLockManager
* endpoint_lock_manager
=
150 WebSocketEndpointLockManager::GetInstance();
152 endpoint_lock_manager
->UnlockEndpoint(CurrentAddress());
154 if (current_address_index_
+ 1 < addresses_
.size()) {
155 // Try falling back to the next address in the list.
156 next_state_
= STATE_OBTAIN_LOCK
;
157 ++current_address_index_
;
164 endpoint_lock_manager
->RememberSocket(transport_socket_
.get(),