1 // Copyright (c) 2012 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 "quiche/quic/tools/quic_client_default_network_helper.h"
6
7 #include "absl/cleanup/cleanup.h"
8 #include "quiche/quic/core/io/quic_event_loop.h"
9 #include "quiche/quic/core/quic_default_packet_writer.h"
10 #include "quiche/quic/core/quic_packets.h"
11 #include "quiche/quic/core/quic_types.h"
12 #include "quiche/quic/core/quic_udp_socket.h"
13 #include "quiche/quic/platform/api/quic_logging.h"
14 #include "quiche/common/platform/api/quiche_logging.h"
15 #include "quiche/common/platform/api/quiche_system_event_loop.h"
16
17 namespace quic {
18
19 namespace {
20
21 // For level-triggered I/O, we need to manually rearm the kSocketEventWritable
22 // listener whenever the socket gets blocked.
23 class LevelTriggeredPacketWriter : public QuicDefaultPacketWriter {
24 public:
LevelTriggeredPacketWriter(int fd,QuicEventLoop * event_loop)25 explicit LevelTriggeredPacketWriter(int fd, QuicEventLoop* event_loop)
26 : QuicDefaultPacketWriter(fd), event_loop_(event_loop) {
27 QUICHE_DCHECK(!event_loop->SupportsEdgeTriggered());
28 }
29
WritePacket(const char * buffer,size_t buf_len,const QuicIpAddress & self_address,const QuicSocketAddress & peer_address,PerPacketOptions * options)30 WriteResult WritePacket(const char* buffer, size_t buf_len,
31 const QuicIpAddress& self_address,
32 const QuicSocketAddress& peer_address,
33 PerPacketOptions* options) override {
34 WriteResult result = QuicDefaultPacketWriter::WritePacket(
35 buffer, buf_len, self_address, peer_address, options);
36 if (IsWriteBlockedStatus(result.status)) {
37 bool success = event_loop_->RearmSocket(fd(), kSocketEventWritable);
38 QUICHE_DCHECK(success);
39 }
40 return result;
41 }
42
43 private:
44 QuicEventLoop* event_loop_;
45 };
46
47 } // namespace
48
QuicClientDefaultNetworkHelper(QuicEventLoop * event_loop,QuicClientBase * client)49 QuicClientDefaultNetworkHelper::QuicClientDefaultNetworkHelper(
50 QuicEventLoop* event_loop, QuicClientBase* client)
51 : event_loop_(event_loop),
52 packets_dropped_(0),
53 overflow_supported_(false),
54 packet_reader_(new QuicPacketReader()),
55 client_(client),
56 max_reads_per_event_loop_(std::numeric_limits<int>::max()) {}
57
~QuicClientDefaultNetworkHelper()58 QuicClientDefaultNetworkHelper::~QuicClientDefaultNetworkHelper() {
59 if (client_->connected()) {
60 client_->session()->connection()->CloseConnection(
61 QUIC_PEER_GOING_AWAY, "Client being torn down",
62 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
63 }
64
65 CleanUpAllUDPSockets();
66 }
67
CreateUDPSocketAndBind(QuicSocketAddress server_address,QuicIpAddress bind_to_address,int bind_to_port)68 bool QuicClientDefaultNetworkHelper::CreateUDPSocketAndBind(
69 QuicSocketAddress server_address, QuicIpAddress bind_to_address,
70 int bind_to_port) {
71 int fd = CreateUDPSocket(server_address, &overflow_supported_);
72 if (fd < 0) {
73 return false;
74 }
75 auto closer = absl::MakeCleanup([fd] { close(fd); });
76
77 QuicSocketAddress client_address;
78 if (bind_to_address.IsInitialized()) {
79 client_address = QuicSocketAddress(bind_to_address, client_->local_port());
80 } else if (server_address.host().address_family() == IpAddressFamily::IP_V4) {
81 client_address = QuicSocketAddress(QuicIpAddress::Any4(), bind_to_port);
82 } else {
83 client_address = QuicSocketAddress(QuicIpAddress::Any6(), bind_to_port);
84 }
85
86 // Some platforms expect that the addrlen given to bind() exactly matches the
87 // size of the associated protocol family's sockaddr struct.
88 // TODO(b/179430548): Revert this when affected platforms are updated to
89 // to support binding with an addrelen of sizeof(sockaddr_storage)
90 socklen_t addrlen;
91 switch (client_address.host().address_family()) {
92 case IpAddressFamily::IP_V4:
93 addrlen = sizeof(sockaddr_in);
94 break;
95 case IpAddressFamily::IP_V6:
96 addrlen = sizeof(sockaddr_in6);
97 break;
98 case IpAddressFamily::IP_UNSPEC:
99 addrlen = 0;
100 break;
101 }
102
103 sockaddr_storage addr = client_address.generic_address();
104 int rc = bind(fd, reinterpret_cast<sockaddr*>(&addr), addrlen);
105 if (rc < 0) {
106 QUIC_LOG(ERROR) << "Bind failed: " << strerror(errno)
107 << " bind_to_address:" << bind_to_address
108 << ", bind_to_port:" << bind_to_port
109 << ", client_address:" << client_address;
110 return false;
111 }
112
113 if (client_address.FromSocket(fd) != 0) {
114 QUIC_LOG(ERROR) << "Unable to get self address. Error: "
115 << strerror(errno);
116 }
117
118 if (event_loop_->RegisterSocket(
119 fd, kSocketEventReadable | kSocketEventWritable, this)) {
120 fd_address_map_[fd] = client_address;
121 std::move(closer).Cancel();
122 return true;
123 }
124 return false;
125 }
126
CleanUpUDPSocket(int fd)127 void QuicClientDefaultNetworkHelper::CleanUpUDPSocket(int fd) {
128 CleanUpUDPSocketImpl(fd);
129 fd_address_map_.erase(fd);
130 }
131
CleanUpAllUDPSockets()132 void QuicClientDefaultNetworkHelper::CleanUpAllUDPSockets() {
133 for (std::pair<int, QuicSocketAddress> fd_address : fd_address_map_) {
134 CleanUpUDPSocketImpl(fd_address.first);
135 }
136 fd_address_map_.clear();
137 }
138
CleanUpUDPSocketImpl(int fd)139 void QuicClientDefaultNetworkHelper::CleanUpUDPSocketImpl(int fd) {
140 if (fd > -1) {
141 bool success = event_loop_->UnregisterSocket(fd);
142 QUICHE_DCHECK(success || fds_unregistered_externally_);
143 int rc = close(fd);
144 QUICHE_DCHECK_EQ(0, rc);
145 }
146 }
147
RunEventLoop()148 void QuicClientDefaultNetworkHelper::RunEventLoop() {
149 quiche::QuicheRunSystemEventLoopIteration();
150 event_loop_->RunEventLoopOnce(QuicTime::Delta::FromMilliseconds(50));
151 }
152
OnSocketEvent(QuicEventLoop *,QuicUdpSocketFd fd,QuicSocketEventMask events)153 void QuicClientDefaultNetworkHelper::OnSocketEvent(
154 QuicEventLoop* /*event_loop*/, QuicUdpSocketFd fd,
155 QuicSocketEventMask events) {
156 if (events & kSocketEventReadable) {
157 QUIC_DVLOG(1) << "Read packets on kSocketEventReadable";
158 int times_to_read = max_reads_per_event_loop_;
159 bool more_to_read = true;
160 QuicPacketCount packets_dropped = 0;
161 while (client_->connected() && more_to_read && times_to_read > 0) {
162 more_to_read = packet_reader_->ReadAndDispatchPackets(
163 fd, GetLatestClientAddress().port(), *client_->helper()->GetClock(),
164 this, overflow_supported_ ? &packets_dropped : nullptr);
165 --times_to_read;
166 }
167 if (packets_dropped_ < packets_dropped) {
168 QUIC_LOG(ERROR)
169 << packets_dropped - packets_dropped_
170 << " more packets are dropped in the socket receive buffer.";
171 packets_dropped_ = packets_dropped;
172 }
173 if (client_->connected() && more_to_read) {
174 bool success =
175 event_loop_->ArtificiallyNotifyEvent(fd, kSocketEventReadable);
176 QUICHE_DCHECK(success);
177 } else if (!event_loop_->SupportsEdgeTriggered()) {
178 bool success = event_loop_->RearmSocket(fd, kSocketEventReadable);
179 QUICHE_DCHECK(success);
180 }
181 }
182 if (client_->connected() && (events & kSocketEventWritable)) {
183 client_->writer()->SetWritable();
184 client_->session()->connection()->OnCanWrite();
185 }
186 }
187
CreateQuicPacketWriter()188 QuicPacketWriter* QuicClientDefaultNetworkHelper::CreateQuicPacketWriter() {
189 if (event_loop_->SupportsEdgeTriggered()) {
190 return new QuicDefaultPacketWriter(GetLatestFD());
191 } else {
192 return new LevelTriggeredPacketWriter(GetLatestFD(), event_loop_);
193 }
194 }
195
SetClientPort(int port)196 void QuicClientDefaultNetworkHelper::SetClientPort(int port) {
197 fd_address_map_.back().second =
198 QuicSocketAddress(GetLatestClientAddress().host(), port);
199 }
200
GetLatestClientAddress() const201 QuicSocketAddress QuicClientDefaultNetworkHelper::GetLatestClientAddress()
202 const {
203 if (fd_address_map_.empty()) {
204 return QuicSocketAddress();
205 }
206
207 return fd_address_map_.back().second;
208 }
209
GetLatestFD() const210 int QuicClientDefaultNetworkHelper::GetLatestFD() const {
211 if (fd_address_map_.empty()) {
212 return -1;
213 }
214
215 return fd_address_map_.back().first;
216 }
217
ProcessPacket(const QuicSocketAddress & self_address,const QuicSocketAddress & peer_address,const QuicReceivedPacket & packet)218 void QuicClientDefaultNetworkHelper::ProcessPacket(
219 const QuicSocketAddress& self_address,
220 const QuicSocketAddress& peer_address, const QuicReceivedPacket& packet) {
221 client_->session()->ProcessUdpPacket(self_address, peer_address, packet);
222 }
223
CreateUDPSocket(QuicSocketAddress server_address,bool * overflow_supported)224 int QuicClientDefaultNetworkHelper::CreateUDPSocket(
225 QuicSocketAddress server_address, bool* overflow_supported) {
226 QuicUdpSocketApi api;
227 int fd = api.Create(server_address.host().AddressFamilyToInt(),
228 /*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
229 /*send_buffer_size =*/kDefaultSocketReceiveBuffer);
230 if (fd < 0) {
231 return fd;
232 }
233
234 *overflow_supported = api.EnableDroppedPacketCount(fd);
235 api.EnableReceiveTimestamp(fd);
236
237 if (!BindInterfaceNameIfNeeded(fd)) {
238 CleanUpUDPSocket(fd);
239 return kQuicInvalidSocketFd;
240 }
241
242 return fd;
243 }
244
BindInterfaceNameIfNeeded(int fd)245 bool QuicClientDefaultNetworkHelper::BindInterfaceNameIfNeeded(int fd) {
246 QuicUdpSocketApi api;
247 std::string interface_name = client_->interface_name();
248 if (!interface_name.empty()) {
249 if (!api.BindInterface(fd, interface_name)) {
250 QUIC_DLOG(WARNING) << "Failed to bind socket (" << fd
251 << ") to interface (" << interface_name << ").";
252 return false;
253 }
254 }
255 return true;
256 }
257
258 } // namespace quic
259