OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/socket/websocket_transport_connect_sub_job.h" | |
6 | |
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" | |
13 | |
14 namespace net { | |
15 | |
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) {} | |
25 | |
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()); | |
35 } | |
36 } | |
37 | |
38 // Start connecting. | |
39 int WebSocketTransportConnectSubJob::Start() { | |
40 DCHECK_EQ(STATE_NONE, next_state_); | |
41 next_state_ = STATE_OBTAIN_LOCK; | |
42 return DoLoop(OK); | |
43 } | |
44 | |
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); | |
49 } | |
50 | |
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; | |
63 } | |
64 NOTREACHED(); | |
65 return LOAD_STATE_IDLE; | |
66 } | |
67 | |
68 ClientSocketFactory* WebSocketTransportConnectSubJob::client_socket_factory() | |
69 const { | |
70 return parent_job_->helper_.client_socket_factory(); | |
71 } | |
72 | |
73 const BoundNetLog& WebSocketTransportConnectSubJob::net_log() const { | |
74 return parent_job_->net_log(); | |
75 } | |
76 | |
77 const IPEndPoint& WebSocketTransportConnectSubJob::CurrentAddress() const { | |
78 DCHECK_LT(current_address_index_, addresses_.size()); | |
79 return addresses_[current_address_index_]; | |
80 } | |
81 | |
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 | |
86 } | |
87 | |
88 int WebSocketTransportConnectSubJob::DoLoop(int result) { | |
89 DCHECK_NE(next_state_, STATE_NONE); | |
90 | |
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; | |
115 } | |
116 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE && | |
117 next_state_ != STATE_DONE); | |
118 | |
119 return rv; | |
120 } | |
121 | |
122 int WebSocketTransportConnectSubJob::DoEndpointLock() { | |
123 int rv = WebSocketEndpointLockManager::GetInstance()->LockEndpoint( | |
124 CurrentAddress(), this); | |
125 next_state_ = STATE_OBTAIN_LOCK_COMPLETE; | |
126 return rv; | |
127 } | |
128 | |
129 int WebSocketTransportConnectSubJob::DoEndpointLockComplete() { | |
130 next_state_ = STATE_TRANSPORT_CONNECT; | |
131 return OK; | |
132 } | |
133 | |
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))); | |
145 } | |
146 | |
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()); | |
153 | |
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; | |
159 } | |
160 | |
161 return result; | |
162 } | |
163 | |
164 endpoint_lock_manager->RememberSocket(transport_socket_.get(), | |
165 CurrentAddress()); | |
166 | |
167 return result; | |
168 } | |
169 | |
170 } // namespace net | |
OLD | NEW |