1 // Copyright 2024 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/tcp_stream_attempt.h"
6
7 #include <memory>
8 #include <string_view>
9
10 #include "base/time/time.h"
11 #include "base/timer/timer.h"
12 #include "base/values.h"
13 #include "net/base/address_list.h"
14 #include "net/base/net_errors.h"
15 #include "net/socket/client_socket_factory.h"
16 #include "net/socket/socket_performance_watcher.h"
17 #include "net/socket/socket_performance_watcher_factory.h"
18 #include "net/socket/transport_client_socket.h"
19
20 namespace net {
21
22 // static
StateToString(State state)23 std::string_view TcpStreamAttempt::StateToString(State state) {
24 switch (state) {
25 case State::kNone:
26 return "None";
27 case State::kConnecting:
28 return "Connecting";
29 }
30 }
31
TcpStreamAttempt(const StreamAttemptParams * params,IPEndPoint ip_endpoint,const NetLogWithSource * net_log)32 TcpStreamAttempt::TcpStreamAttempt(const StreamAttemptParams* params,
33 IPEndPoint ip_endpoint,
34 const NetLogWithSource* net_log)
35 : StreamAttempt(params,
36 ip_endpoint,
37 NetLogSourceType::TCP_STREAM_ATTEMPT,
38 NetLogEventType::TCP_STREAM_ATTEMPT_ALIVE,
39 net_log) {}
40
41 TcpStreamAttempt::~TcpStreamAttempt() = default;
42
GetLoadState() const43 LoadState TcpStreamAttempt::GetLoadState() const {
44 switch (next_state_) {
45 case State::kNone:
46 return LOAD_STATE_IDLE;
47 case State::kConnecting:
48 return LOAD_STATE_CONNECTING;
49 }
50 }
51
GetInfoAsValue() const52 base::Value::Dict TcpStreamAttempt::GetInfoAsValue() const {
53 base::Value::Dict dict;
54 dict.Set("next_state", StateToString(next_state_));
55 return dict;
56 }
57
StartInternal()58 int TcpStreamAttempt::StartInternal() {
59 next_state_ = State::kConnecting;
60
61 std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher;
62 if (params().socket_performance_watcher_factory) {
63 socket_performance_watcher =
64 params()
65 .socket_performance_watcher_factory->CreateSocketPerformanceWatcher(
66 SocketPerformanceWatcherFactory::PROTOCOL_TCP,
67 ip_endpoint().address());
68 }
69
70 std::unique_ptr<TransportClientSocket> stream_socket =
71 params().client_socket_factory->CreateTransportClientSocket(
72 AddressList(ip_endpoint()), std::move(socket_performance_watcher),
73 params().network_quality_estimator, net_log().net_log(),
74 net_log().source());
75
76 TransportClientSocket* socket_ptr = stream_socket.get();
77 SetStreamSocket(std::move(stream_socket));
78
79 mutable_connect_timing().connect_start = base::TimeTicks::Now();
80 CHECK(!timeout_timer_.IsRunning());
81 timeout_timer_.Start(
82 FROM_HERE, kTcpHandshakeTimeout,
83 base::BindOnce(&TcpStreamAttempt::OnTimeout, base::Unretained(this)));
84
85 net_log().AddEventReferencingSource(
86 NetLogEventType::TCP_STREAM_ATTEMPT_CONNECT,
87 socket_ptr->NetLog().source());
88 int rv = socket_ptr->Connect(
89 base::BindOnce(&TcpStreamAttempt::OnIOComplete, base::Unretained(this)));
90 if (rv != ERR_IO_PENDING) {
91 HandleCompletion();
92 }
93 return rv;
94 }
95
GetNetLogStartParams()96 base::Value::Dict TcpStreamAttempt::GetNetLogStartParams() {
97 base::Value::Dict dict;
98 dict.Set("ip_endpoint", ip_endpoint().ToString());
99 return dict;
100 }
101
HandleCompletion()102 void TcpStreamAttempt::HandleCompletion() {
103 next_state_ = State::kNone;
104 timeout_timer_.Stop();
105 mutable_connect_timing().connect_end = base::TimeTicks::Now();
106 }
107
OnIOComplete(int rv)108 void TcpStreamAttempt::OnIOComplete(int rv) {
109 CHECK_NE(rv, ERR_IO_PENDING);
110 HandleCompletion();
111 NotifyOfCompletion(rv);
112 }
113
OnTimeout()114 void TcpStreamAttempt::OnTimeout() {
115 SetStreamSocket(nullptr);
116 // TODO(bashi): The error code should be ERR_CONNECTION_TIMED_OUT but use
117 // ERR_TIMED_OUT for consistency with ConnectJobs.
118 OnIOComplete(ERR_TIMED_OUT);
119 }
120
121 } // namespace net
122