Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / socket / websocket_transport_connect_sub_job.cc
blob25c0744cfac75a10a32d35bb9bee4cec80831794
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/log/net_log.h"
11 #include "net/socket/client_socket_factory.h"
12 #include "net/socket/websocket_endpoint_lock_manager.h"
14 namespace net {
16 WebSocketTransportConnectSubJob::WebSocketTransportConnectSubJob(
17 const AddressList& addresses,
18 WebSocketTransportConnectJob* parent_job,
19 SubJobType type)
20 : parent_job_(parent_job),
21 addresses_(addresses),
22 current_address_index_(0),
23 next_state_(STATE_NONE),
24 type_(type) {}
26 WebSocketTransportConnectSubJob::~WebSocketTransportConnectSubJob() {
27 // We don't worry about cancelling the TCP connect, since ~StreamSocket will
28 // take care of it.
29 if (next()) {
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(
34 CurrentAddress());
38 // Start connecting.
39 int WebSocketTransportConnectSubJob::Start() {
40 DCHECK_EQ(STATE_NONE, next_state_);
41 next_state_ = STATE_OBTAIN_LOCK;
42 return DoLoop(OK);
45 // Called by WebSocketEndpointLockManager when the lock becomes available.
46 void WebSocketTransportConnectSubJob::GotEndpointLock() {
47 DCHECK_EQ(STATE_OBTAIN_LOCK_COMPLETE, next_state_);
48 OnIOComplete(OK);
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:
59 case STATE_DONE:
60 return LOAD_STATE_CONNECTING;
61 case STATE_NONE:
62 return LOAD_STATE_IDLE;
64 NOTREACHED();
65 return LOAD_STATE_IDLE;
68 ClientSocketFactory* WebSocketTransportConnectSubJob::client_socket_factory()
69 const {
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);
91 int rv = result;
92 do {
93 State state = next_state_;
94 next_state_ = STATE_NONE;
95 switch (state) {
96 case STATE_OBTAIN_LOCK:
97 DCHECK_EQ(OK, rv);
98 rv = DoEndpointLock();
99 break;
100 case STATE_OBTAIN_LOCK_COMPLETE:
101 DCHECK_EQ(OK, rv);
102 rv = DoEndpointLockComplete();
103 break;
104 case STATE_TRANSPORT_CONNECT:
105 DCHECK_EQ(OK, rv);
106 rv = DoTransportConnect();
107 break;
108 case STATE_TRANSPORT_CONNECT_COMPLETE:
109 rv = DoTransportConnectComplete(rv);
110 break;
111 default:
112 NOTREACHED();
113 rv = ERR_FAILED;
114 break;
116 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
117 next_state_ != STATE_DONE);
119 return rv;
122 int WebSocketTransportConnectSubJob::DoEndpointLock() {
123 int rv = WebSocketEndpointLockManager::GetInstance()->LockEndpoint(
124 CurrentAddress(), this);
125 next_state_ = STATE_OBTAIN_LOCK_COMPLETE;
126 return rv;
129 int WebSocketTransportConnectSubJob::DoEndpointLockComplete() {
130 next_state_ = STATE_TRANSPORT_CONNECT;
131 return OK;
134 int WebSocketTransportConnectSubJob::DoTransportConnect() {
135 // TODO(ricea): Update global g_last_connect_time and report
136 // ConnectInterval.
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();
151 if (result != OK) {
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_;
158 result = OK;
161 return result;
164 endpoint_lock_manager->RememberSocket(transport_socket_.get(),
165 CurrentAddress());
167 return result;
170 } // namespace net