Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / net / socket / websocket_transport_connect_sub_job.cc
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