• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
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/transport_connect_sub_job.h"
6 
7 #include <set>
8 #include <string>
9 #include <utility>
10 
11 #include "base/check_op.h"
12 #include "base/functional/bind.h"
13 #include "base/notreached.h"
14 #include "net/base/ip_endpoint.h"
15 #include "net/base/net_errors.h"
16 #include "net/log/net_log_with_source.h"
17 #include "net/socket/client_socket_factory.h"
18 #include "net/socket/connection_attempts.h"
19 #include "net/socket/socket_performance_watcher.h"
20 #include "net/socket/socket_performance_watcher_factory.h"
21 #include "net/socket/websocket_endpoint_lock_manager.h"
22 
23 namespace net {
24 
25 namespace {
26 
27 // StreamSocket wrapper that registers/unregisters the wrapped StreamSocket with
28 // a WebSocketEndpointLockManager on creation/destruction.
29 class WebSocketStreamSocket final : public StreamSocket {
30  public:
WebSocketStreamSocket(std::unique_ptr<StreamSocket> wrapped_socket,WebSocketEndpointLockManager * websocket_endpoint_lock_manager,const IPEndPoint & address)31   WebSocketStreamSocket(
32       std::unique_ptr<StreamSocket> wrapped_socket,
33       WebSocketEndpointLockManager* websocket_endpoint_lock_manager,
34       const IPEndPoint& address)
35       : wrapped_socket_(std::move(wrapped_socket)),
36         lock_releaser_(websocket_endpoint_lock_manager, address) {}
37 
38   WebSocketStreamSocket(const WebSocketStreamSocket&) = delete;
39   WebSocketStreamSocket& operator=(const WebSocketStreamSocket&) = delete;
40 
41   ~WebSocketStreamSocket() override = default;
42 
43   // Socket implementation:
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)44   int Read(IOBuffer* buf,
45            int buf_len,
46            CompletionOnceCallback callback) override {
47     return wrapped_socket_->Read(buf, buf_len, std::move(callback));
48   }
ReadIfReady(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)49   int ReadIfReady(IOBuffer* buf,
50                   int buf_len,
51                   CompletionOnceCallback callback) override {
52     return wrapped_socket_->ReadIfReady(buf, buf_len, std::move(callback));
53   }
CancelReadIfReady()54   int CancelReadIfReady() override {
55     return wrapped_socket_->CancelReadIfReady();
56   }
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag & traffic_annotation)57   int Write(IOBuffer* buf,
58             int buf_len,
59             CompletionOnceCallback callback,
60             const NetworkTrafficAnnotationTag& traffic_annotation) override {
61     return wrapped_socket_->Write(buf, buf_len, std::move(callback),
62                                   traffic_annotation);
63   }
SetReceiveBufferSize(int32_t size)64   int SetReceiveBufferSize(int32_t size) override {
65     return wrapped_socket_->SetReceiveBufferSize(size);
66   }
SetSendBufferSize(int32_t size)67   int SetSendBufferSize(int32_t size) override {
68     return wrapped_socket_->SetSendBufferSize(size);
69   }
SetDnsAliases(std::set<std::string> aliases)70   void SetDnsAliases(std::set<std::string> aliases) override {
71     wrapped_socket_->SetDnsAliases(std::move(aliases));
72   }
GetDnsAliases() const73   const std::set<std::string>& GetDnsAliases() const override {
74     return wrapped_socket_->GetDnsAliases();
75   }
76 
77   // StreamSocket implementation:
Connect(CompletionOnceCallback callback)78   int Connect(CompletionOnceCallback callback) override {
79     return wrapped_socket_->Connect(std::move(callback));
80   }
Disconnect()81   void Disconnect() override { wrapped_socket_->Disconnect(); }
IsConnected() const82   bool IsConnected() const override { return wrapped_socket_->IsConnected(); }
IsConnectedAndIdle() const83   bool IsConnectedAndIdle() const override {
84     return wrapped_socket_->IsConnectedAndIdle();
85   }
GetPeerAddress(IPEndPoint * address) const86   int GetPeerAddress(IPEndPoint* address) const override {
87     return wrapped_socket_->GetPeerAddress(address);
88   }
GetLocalAddress(IPEndPoint * address) const89   int GetLocalAddress(IPEndPoint* address) const override {
90     return wrapped_socket_->GetLocalAddress(address);
91   }
NetLog() const92   const NetLogWithSource& NetLog() const override {
93     return wrapped_socket_->NetLog();
94   }
WasEverUsed() const95   bool WasEverUsed() const override { return wrapped_socket_->WasEverUsed(); }
WasAlpnNegotiated() const96   bool WasAlpnNegotiated() const override {
97     return wrapped_socket_->WasAlpnNegotiated();
98   }
GetNegotiatedProtocol() const99   NextProto GetNegotiatedProtocol() const override {
100     return wrapped_socket_->GetNegotiatedProtocol();
101   }
GetSSLInfo(SSLInfo * ssl_info)102   bool GetSSLInfo(SSLInfo* ssl_info) override {
103     return wrapped_socket_->GetSSLInfo(ssl_info);
104   }
GetTotalReceivedBytes() const105   int64_t GetTotalReceivedBytes() const override {
106     return wrapped_socket_->GetTotalReceivedBytes();
107   }
ApplySocketTag(const SocketTag & tag)108   void ApplySocketTag(const SocketTag& tag) override {
109     wrapped_socket_->ApplySocketTag(tag);
110   }
111 
112  private:
113   std::unique_ptr<StreamSocket> wrapped_socket_;
114   WebSocketEndpointLockManager::LockReleaser lock_releaser_;
115 };
116 
117 }  // namespace
118 
TransportConnectSubJob(std::vector<IPEndPoint> addresses,TransportConnectJob * parent_job,SubJobType type)119 TransportConnectSubJob::TransportConnectSubJob(
120     std::vector<IPEndPoint> addresses,
121     TransportConnectJob* parent_job,
122     SubJobType type)
123     : parent_job_(parent_job), addresses_(std::move(addresses)), type_(type) {}
124 
125 TransportConnectSubJob::~TransportConnectSubJob() = default;
126 
127 // Start connecting.
Start()128 int TransportConnectSubJob::Start() {
129   DCHECK_EQ(STATE_NONE, next_state_);
130   next_state_ = STATE_OBTAIN_LOCK;
131   return DoLoop(OK);
132 }
133 
134 // Called by WebSocketEndpointLockManager when the lock becomes available.
GotEndpointLock()135 void TransportConnectSubJob::GotEndpointLock() {
136   DCHECK_EQ(STATE_OBTAIN_LOCK_COMPLETE, next_state_);
137   OnIOComplete(OK);
138 }
139 
GetLoadState() const140 LoadState TransportConnectSubJob::GetLoadState() const {
141   switch (next_state_) {
142     case STATE_OBTAIN_LOCK:
143     case STATE_OBTAIN_LOCK_COMPLETE:
144       // TODO(ricea): Add a WebSocket-specific LOAD_STATE ?
145       return LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET;
146     case STATE_TRANSPORT_CONNECT_COMPLETE:
147     case STATE_DONE:
148       return LOAD_STATE_CONNECTING;
149     case STATE_NONE:
150       return LOAD_STATE_IDLE;
151   }
152   NOTREACHED();
153   return LOAD_STATE_IDLE;
154 }
155 
CurrentAddress() const156 const IPEndPoint& TransportConnectSubJob::CurrentAddress() const {
157   DCHECK_LT(current_address_index_, addresses_.size());
158   return addresses_[current_address_index_];
159 }
160 
OnIOComplete(int result)161 void TransportConnectSubJob::OnIOComplete(int result) {
162   int rv = DoLoop(result);
163   if (rv != ERR_IO_PENDING)
164     parent_job_->OnSubJobComplete(rv, this);  // |this| deleted
165 }
166 
DoLoop(int result)167 int TransportConnectSubJob::DoLoop(int result) {
168   DCHECK_NE(next_state_, STATE_NONE);
169 
170   int rv = result;
171   do {
172     State state = next_state_;
173     next_state_ = STATE_NONE;
174     switch (state) {
175       case STATE_OBTAIN_LOCK:
176         DCHECK_EQ(OK, rv);
177         rv = DoEndpointLock();
178         break;
179       case STATE_OBTAIN_LOCK_COMPLETE:
180         DCHECK_EQ(OK, rv);
181         rv = DoEndpointLockComplete();
182         break;
183       case STATE_TRANSPORT_CONNECT_COMPLETE:
184         rv = DoTransportConnectComplete(rv);
185         break;
186       default:
187         NOTREACHED();
188         rv = ERR_FAILED;
189         break;
190     }
191   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
192            next_state_ != STATE_DONE);
193 
194   return rv;
195 }
196 
DoEndpointLock()197 int TransportConnectSubJob::DoEndpointLock() {
198   next_state_ = STATE_OBTAIN_LOCK_COMPLETE;
199   if (!parent_job_->websocket_endpoint_lock_manager()) {
200     return OK;
201   }
202   return parent_job_->websocket_endpoint_lock_manager()->LockEndpoint(
203       CurrentAddress(), this);
204 }
205 
DoEndpointLockComplete()206 int TransportConnectSubJob::DoEndpointLockComplete() {
207   next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
208   AddressList one_address(CurrentAddress());
209 
210   // Create a `SocketPerformanceWatcher`, and pass the ownership.
211   std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher;
212   if (auto* factory = parent_job_->socket_performance_watcher_factory();
213       factory != nullptr) {
214     socket_performance_watcher = factory->CreateSocketPerformanceWatcher(
215         SocketPerformanceWatcherFactory::PROTOCOL_TCP,
216         CurrentAddress().address());
217   }
218 
219   const NetLogWithSource& net_log = parent_job_->net_log();
220   transport_socket_ =
221       parent_job_->client_socket_factory()->CreateTransportClientSocket(
222           one_address, std::move(socket_performance_watcher),
223           parent_job_->network_quality_estimator(), net_log.net_log(),
224           net_log.source());
225 
226   net_log.AddEvent(NetLogEventType::TRANSPORT_CONNECT_JOB_CONNECT_ATTEMPT, [&] {
227     base::Value::Dict dict;
228     dict.Set("address", CurrentAddress().ToString());
229     transport_socket_->NetLog().source().AddToEventParameters(dict);
230     return dict;
231   });
232 
233   // If `websocket_endpoint_lock_manager_` is non-null, this class now owns an
234   // endpoint lock. Wrap `socket` in a `WebSocketStreamSocket` to take ownership
235   // of the lock and release it when the socket goes out of scope. This must
236   // happen before any early returns in this method.
237   if (parent_job_->websocket_endpoint_lock_manager()) {
238     transport_socket_ = std::make_unique<WebSocketStreamSocket>(
239         std::move(transport_socket_),
240         parent_job_->websocket_endpoint_lock_manager(), CurrentAddress());
241   }
242 
243   transport_socket_->ApplySocketTag(parent_job_->socket_tag());
244 
245   // This use of base::Unretained() is safe because transport_socket_ is
246   // destroyed in the destructor.
247   return transport_socket_->Connect(base::BindOnce(
248       &TransportConnectSubJob::OnIOComplete, base::Unretained(this)));
249 }
250 
DoTransportConnectComplete(int result)251 int TransportConnectSubJob::DoTransportConnectComplete(int result) {
252   next_state_ = STATE_DONE;
253   if (result != OK) {
254     // Drop the socket to release the endpoint lock, if any.
255     transport_socket_.reset();
256 
257     parent_job_->connection_attempts_.push_back(
258         ConnectionAttempt(CurrentAddress(), result));
259 
260     // Don't try the next address if entering suspend mode.
261     if (result != ERR_NETWORK_IO_SUSPENDED &&
262         current_address_index_ + 1 < addresses_.size()) {
263       // Try falling back to the next address in the list.
264       next_state_ = STATE_OBTAIN_LOCK;
265       ++current_address_index_;
266       result = OK;
267     }
268 
269     return result;
270   }
271 
272   return result;
273 }
274 
275 }  // namespace net
276